private void OperationProc(object state)
        {
            var operationInWorkState    = (OperationInWorkState)state;
            var newOperationInWorkState = new OperationInWorkState(operationInWorkState.Operation, Thread.CurrentThread);

            this.operationsInWork.TryUpdate(operationInWorkState.Operation.Id, newOperationInWorkState, operationInWorkState);

            try
            {
                Log.Debug("Started operation in thread " + Thread.CurrentThread.ManagedThreadId);
                operationInWorkState.Operation.Invoke();
                Log.Debug("Ended operation in thread " + Thread.CurrentThread.ManagedThreadId);
            }
            catch (Exception ex)
            {
                Log.Error("Operation execution error in thread " + Thread.CurrentThread.ManagedThreadId, ex);
                throw;
            }
            finally
            {
                this.operationsInWork.TryRemove(operationInWorkState.Operation.Id, out operationInWorkState);
                Interlocked.Decrement(ref this.runningThreads);
                this.simultaneouslyRunningLimit.Set();
            }
        }
        private void OperationsLoop(object state)
        {
            Log.Debug("Started operation loop in thread " + Thread.CurrentThread.ManagedThreadId);

            do
            {
                lock (this.operationLoopSync)
                {
                    if (!(this.operationLoop = !this.stop && !this.operationQueue.IsEmpty))
                    {
                        // Wait before all sub threads are done.
                        if (this.runningThreads > 0)
                        {
                            this.simultaneouslyRunningLimit.Reset();
                            this.operationLoop = true;
                        }
                        else
                        {
                            break;
                        }
                    }
                }

                if (this.pause)
                {
                    this.simultaneouslyRunningLimit.Reset();
                }

                // Here waiting opration add or available free thread.
                this.simultaneouslyRunningLimit.Wait();

                if (this.stop || this.pause)
                {
                    continue;
                }

                var possibleMaxThreads = this.GetPossibleMaxThreads();

                // If system cannot run simultaneously one more thread or queue is empty then sleep on wait.
                if ((this.runningThreads == 0 && possibleMaxThreads <= this.runningThreads) || this.operationQueue.IsEmpty)
                {
                    this.simultaneouslyRunningLimit.Reset();
                    continue;
                }

                MultiThreadExecutorOperation operation;

                // If can not take operation in the processing then spend time on loop turn :o).
                if (this.operationQueue.TryDequeue(out operation))
                {
                    Interlocked.Increment(ref this.runningThreads);
                    var operationInWorkState = new OperationInWorkState(operation, null);
                    this.operationsInWork.TryAdd(operation.Id, operationInWorkState);
                    ThreadPool.QueueUserWorkItem(this.OperationProc, operationInWorkState);
                }
            }while (true);

            Log.Debug("Ended operation loop in thread " + Thread.CurrentThread.ManagedThreadId);
        }