private void Runner() { CancellationTokenSource?.Dispose(); CancellationTokenSource = new CancellationTokenSource(); CancellationToken = CancellationTokenSource.Token; MessageDataItem message = null; while (true) { if (SpinWait.SpinUntil(() => AttachedQueue.TryTake(out message), 1)) { ProcessMessage(message); // assume there are more messages // NB! No need to test CancellationToken in this loop, because it's a kind of attempt to drain the queue. If not achieved in-time, // will be terminated forcibly. while (AttachedQueue.TryTake(out message)) { ProcessMessage(message); } } // no messages left if (CancellationToken.IsCancellationRequested) { break; } } // All done, but let's drain the queue -- if anything left it will never be completed while (AttachedQueue.Count > 0) { Thread.Sleep(5); } WorkCompleted.Set(); }