0

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.

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. 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. 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):

    /// <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?

Fleve
  • 400
  • 1
  • 5
  • 19

1 Answers1

1

Taffer has some good advice there, but since you've got so many background worker threads it's gotten more complicated.

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.

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. I suppose you could pass a reference to the thread through DoWorkEventArgs.Argument and check CancellationPending on that. I've not tried it but it seems like it could work.

Spike
  • 2,016
  • 12
  • 27