可取消的线程队列

时间:2015-09-30 08:40:10

标签: c# multithreading winforms

在我们的几何编辑软件中,当用户更改几何体的某些参数(例如某些几何图形的大小或位置)时,应获取并显示几何图形中的“有趣”主要点列表在一张桌子里。因为获得这些点有时会持续几秒钟,所以我们决定使用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
        }
    }

我现在发现的问题是,虽然不会显示结果,但后台可能会运行很多线程。我已经搜索过,目前尚不清楚是否以及如何“杀死”线程。但也许我可以控制一下如果这些。有什么建议吗?

1 个答案:

答案 0 :(得分:1)

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

如果你想一次性停止所有这些,你可以通过DoWorkEventArgs.Argument将CancellationToken传递给线程,然后你可以检查令牌是否在backgroundWorker_DoWork中被取消,并且从后面的workWorker_DoWork中取消你只需取消一个CancellationTokenSource

如果你需要个别杀死它们,你需要跟踪它们。把它们放在某种集合中。您仍然可以调用CancelAsync(),但是从backgroundWorker_DoWork内部很难知道哪个线程是您的。我想你可以通过DoWorkEventArgs.Argument传递对线程的引用,并检查CancellationPending。我没试过,但似乎它可以工作。