C# Correctly aborting a always running thread with a BlockingCollection

Viewed 626

I am running a thread that has a

while(isRunning) 
{ 
    blockingCollection.Take()
}

First I am setting isRunning to false. Then I call thread.Interrupt which stops the blockingCollection from waiting for new items. After that I call my Dispose Method for the class running the Thread inside the catch block.

Is that the best/correct way to do this?

2 Answers

A BlockingCollection has a CompleteAdding() method and full support for Cancellation.

while(isRunning && ! blockingCollection.IsCompleted) 
{ 
   isRunning = blockingCollection.TryTake(out someThing, -1, cancelToken);
}

This way you can and should let the Thread end normally, always the better option.

Further to Henk's answer, if you'd rather have the blocking ability of Take() but need to cancel out while its waiting on an empty list, you can handle cancellation out of the loop in this way.

private void DoSomething(CancellationToken token)
{
    while (IsRunning)
    {
        MyObject next;
        try
        {
            next = _queue.Take(token);
        }
        catch(OperationCanceledException)
        {
            break; //Cancelled
        }

        // Do something with 'next'
    }

    // Cleanup

}

Then, when 'whatever' happens that requires you to kill this loop, even if the list is empty and its stuck blocking on the Take() call, just call Cancel() on your CancellationTokenSource that generated the Token.

Note - For safety, its probably also advised to catch an ObjectDisposedException that Take() can also throw. Check the documentation for details around that and why it might throw.

Related