可取消线程队列

本文关键字:队列 线程 可取消 | 更新日期: 2023-09-27 18:15:19

在我们的几何版软件中,当用户改变几何图形的某些参数(例如某些几何图形的大小或位置)时,应从几何图形中获取"有趣"要点列表,并以表格的形式显示出来。因为获得这些点有时需要几秒钟,所以我们决定使用BackGroundWorkers。

我发现的第一个问题是,我必须控制这些点何时被要求计算,因为我只是想显示属于几何体最后变化的点,而不是最后要在BackGroundWorkers中计算的点。我通过添加2个DateTime变量解决了这个问题:一个节省了实际显示点排队计算的时间,另一个节省了实际线程发送实际计算时的时间。当计算完成后,我比较两个日期,并覆盖实际的点列表,如果它是较新的。我这样做与以下代码(在一个用户控制与DataGridView):

    /// <summary>
    ///     Updates the main points.
    /// </summary>
    /// <param name="track">Track.</param>
    public void UpdateMainPoints(Track track)
    {
        Track = track;
        if (backgroundWorker.IsBusy)
        {
            backgroundWorker = new BackgroundWorker();
            backgroundWorker.DoWork += backgroundWorker_DoWork;
        }
        backgroundWorker.RunWorkerAsync();
    }
    private void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
    {
        try
        {
            Invoke((MethodInvoker) ShowMessage);
        }
        catch
        {
            // ignored because it can be called when the window is already closed and it can not be controlled otherwise
        }
        DateTime jobQueueTime = DateTime.Now;
        List<MainPoint> mainPoints = Track.GetMainPoints(_currentUnit);
        if (DateTime.Compare(jobQueueTime, _shownPointsQueueTime) > 0)
        {
            //It updates the actual main point only if the operation was the last one to be calculated
            _mainPoints = new List<MainPoint>(mainPoints);
            _shownPointsQueueTime = jobQueueTime;
        }
        //Updates the time in which the shown points where queued to be calculated
        try
        {
            Invoke((MethodInvoker)HideMessageAndShowMainPoints);
        }
        catch
        {
            // ignored because it can be called when the window is already closed and it can not be controlled otherwise
        }
    }

我现在发现的问题是,可以有很多线程在后台运行,虽然他们的结果不会显示。我已经搜索过了,不清楚是否以及如何"杀死"线程。但也许我能控制这些。任何建议吗?

可取消线程队列

Taffer有一些很好的建议,但是由于你有这么多后台工作线程,它变得更加复杂。

如果你想一次停止它们,你可以通过DoWorkEventArgs向线程传递一个CancellationToken。参数,然后您可以检查令牌是否在backgroundWorker_DoWork中取消,并且从backgroundWorker_DoWork外部取消一个CancellationTokenSource。

如果你需要逐个杀死他们,你需要跟踪他们。把它们收藏起来。你仍然可以调用CancelAsync(),但从backgroundWorker_DoWork内部很难知道哪个线程是你的。我想你可以通过DoWorkEventArgs传递一个引用到线程。参数并检查CancellationPending。我还没有试过,但它似乎可以工作。