简体   繁体   English

可取消的线程队列

[英]Cancellable threads queue

In our geometry edition software, when the user changes some parameter(s) of the geometry (for example the size or position of some geometric figure) , a list of "interesting" main points from the geometry should be obtained and shown in a table. 在我们的几何编辑软件中,当用户更改几何的某些参数(例如某些几何图形的大小或位置)时,应获取几何中“有趣的”主要点的列表,并将其显示在表格中。 Because obtaining these points can last some seconds sometimes, we decided to use BackGroundWorkers. 由于获取这些点有时会持续几秒钟,因此我们决定使用BackGroundWorkers。

The first problem I found was that I had to control when these points were asked to be calculated because I just wanted to show the ones belonging to the last change in the geometry and not the last ones to be calculated in the BackGroundWorkers. 我发现的第一个问题是,我必须控制何时要求计算这些点,因为我只想显示属于几何中最后一个变化的点,而不是显示BackGroundWorkers中要计算的最后一个点。 I solved the issue by adding 2 DateTime variables: one saves the time when the actual shown points where queued to be calculated and other controls when the actual calculation in the actual thread was sent. 我通过添加2个DateTime变量解决了该问题:一个保存了实际显示的点排队计算的时间,另一个保存了实际线程中的实际计算的发送时间。 When the calculation is done I compare the two dates and overwrite the actual list of points if it is newer. 计算完成后,我将比较两个日期并覆盖点的实际列表(如果较新)。 I do it with the following code (in a User Control with a DataGridView): 我使用以下代码(在具有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
        }
    }

The problem that I find now is that there can be a lot of threads running in the background although their results will not be shown. 我现在发现的问题是,尽管将不会显示其结果,但是在后台可能有很多线程在运行。 I have searched and it is not clear if and how can I "kill" threads. 我已经搜索过,目前尚不清楚是否以及如何“杀死”线程。 But maybe I can control somehow if these. 但是,也许我可以控制这些。 Any suggestion? 有什么建议吗?

Taffer has some good advice there, but since you've got so many background worker threads it's gotten more complicated. Taffer在这里提供了一些很好的建议,但是由于您有太多的后台工作线程,因此变得更加复杂。

If you want to stop all of them at once, you could pass a CancellationToken into the thread through DoWorkEventArgs.Argument, then you can check if the token is cancelled in backgroundWorker_DoWork and from outside backgroundWorker_DoWork you'd just cancel the one CancellationTokenSource. 如果要立即停止所有它们,则可以通过DoWorkEventArgs.Argument将CancellationToken传递到线程中,然后可以检查是否在backgroundWorker_DoWork中取消了该令牌,而从backgroundWorker_DoWork外部则只取消了一个CancellationTokenSource。

If you need to kill them on an individual basis, you'll need to keep track of them. 如果您需要单独杀死它们,则需要跟踪它们。 Put them in some kind of a collection. 将它们放在某种集合中。 You can still call CancelAsync(), but from inside of backgroundWorker_DoWork it's hard to know which thread is yours. 您仍然可以调用CancelAsync(),但是从backgroundWorker_DoWork内部很难知道您的线程是哪个。 I suppose you could pass a reference to the thread through DoWorkEventArgs.Argument and check CancellationPending on that. 我想您可以通过DoWorkEventArgs.Argument传递对该线程的引用,并在其上检查CancellationPending。 I've not tried it but it seems like it could work. 我没有尝试过,但似乎可行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM