private void ProcessMessages(WaitHandle[] handles) { var threadHandles = new List <ThreadTermination>(); do { switch (WaitHandle.WaitAny(handles)) { case 0: _continueWait = false; break; case 1: _communicationManager.HandleCommunicationBlock(_mcb, block => Task.Factory.StartNew(() => { lock (SyncRoot) { threadHandles.Add(StartProcessingThread(block)); } })); break; default: break; } } while (_continueWait); _memoryManager.WaitForBlocksToClose(BufferWaitCount); _memoryManager.FetchRemainingBufferData(data => _messageQueue.Enqueue(data)); lock (SyncRoot) { if (threadHandles.Any()) { var tasks = threadHandles .Select((e, index) => new { ThreadTermination = e, Block = index / NumHandlesPerBlock }) .GroupBy(g => g.Block) .Select(g => g.Select(a => a.ThreadTermination).ToList()) .Select(g => Task.Factory.StartNew(() => { ConsumeException(() => { g.Select(h => h.CancelThreadEvent).ToList().ForEach(h => h.Set()); WaitHandle.WaitAll(g.Select(h => h.ThreadFinishedEvent).ToArray <WaitHandle>(), new TimeSpan(0, 0, 20)); }); })).ToArray(); Task.WaitAll(tasks); threadHandles.Clear(); } } _messageQueue.Enqueue(new byte[0]); }