private void CompressChunk(
            CompressionMode compressionMode, AsyncReadContext <QueueItem> asyncReadContext,
            ConcurrentDictionary <int, byte[]> resultPieces, CancellationTokenSource exceptionSrc,
            CancellationToken[] cancellationTokens,
            ManualResetEventSlim outputOverflowEvent)
        {
            try
            {
                while (!cancellationTokens.Any(ct => ct.IsCancellationRequested) || asyncReadContext.Queue.Count > 0)
                {
                    outputOverflowEvent.Wait();

                    if (!asyncReadContext.Queue.TryTake(out var queueItem))
                    {
                        asyncReadContext.EmptyInputEvent.Reset();
                        asyncReadContext.EmptyInputEvent.Wait(TimeSpan.FromMilliseconds(10));
                        continue;
                    }

                    byte[] data;
                    switch (compressionMode)
                    {
                    case CompressionMode.Compress:
                        data = _compressionService.Compress(queueItem.Data);
                        break;

                    case CompressionMode.Decompress:
                        data = _compressionService.Decompress(queueItem.Data);
                        break;

                    default:
                        throw new ApplicationException($"Managing of compression mode '{compressionMode}' not implemented'");
                    }
                    resultPieces.AddOrUpdate(queueItem.Order, data, (i1, byteArray) => byteArray);

                    ControlInputOverflow(asyncReadContext.Queue, asyncReadContext.InputOverflowEvent);
                }
            }
            catch (Exception e)
            {
                _statusUpdateService.Error(e.Message);
                exceptionSrc.Cancel();
            }
        }
        public ParallelCompressionContext Run(CompressionMode compressionMode, int threadsCount, AsyncReadContext <QueueItem> asyncReadContext)
        {
            var threads             = new List <Thread>(threadsCount);
            var resultsDictionary   = new ConcurrentDictionary <int, byte[]>();
            var exceptionSrc        = new CancellationTokenSource();
            var tokens              = new [] { asyncReadContext.ReadFinishedSource.Token, asyncReadContext.ExceptionSource.Token, exceptionSrc.Token };
            var outputOverflowEvent = new ManualResetEventSlim(true);

            for (int i = 0; i < threadsCount; i++)
            {
                var thread = new Thread(() => CompressChunk(compressionMode, asyncReadContext, resultsDictionary,
                                                            exceptionSrc, tokens.ToArray(), outputOverflowEvent));
                threads.Add(thread);
                thread.Start();
            }

            return(new ParallelCompressionContext(threads, resultsDictionary, exceptionSrc, outputOverflowEvent));
        }