private static void ManageThreads(string inputName, string outputName, ArchAction act, int bufferSize, uint workersCount = 0) { InOutBuffer[] buffers = null; ThreadWorker[] workers = null; try { General.Log($"Started '{inputName}' {act} into '{outputName}'..."); if (bufferSize < defaultChunkSize) { bufferSize = defaultChunkSize; } if (workersCount < 1) { workersCount = ChooseWorkersCount(); } General.Log($"buffer size {bufferSize}, workers count {workersCount}"); //to feel good let's use 'using' // objects for input reading using FileStream inFileStream = File.OpenRead(inputName); ArchReader reader = new ArchReader(inFileStream, act); using ThreadWorker readerThread = new ThreadWorker(reader, true); // objects for output writing using FileStream outFileStream = File.Create(outputName); ArchWriter writer = new ArchWriter(outFileStream, act); using ThreadWorker writerThread = new ThreadWorker(writer, true); // create objects to do zipping/unzipping CreateBuffersAndWorkers(act, bufferSize, workersCount, out buffers, out workers); StartConveyor(reader, readerThread, workers, buffers); int idx = 0; // as long as there are bytes read from input, keep conveyor // when no more input data, set this flag & wait till all therads are finihed. bool finishing = false; do { ThreadWorker worker = workers[idx]; if (worker == null) { General.Log($"all threads are finished"); // good place to let the writer go writerThread.Finish(); //writerThread.Dispose(); break; } General.Log($"main thread about to Wait for worker {idx} done, to start writting"); worker.notifyDone.WaitOne(); //wait till zipper idx has done General.Log($"{idx} start writting"); writer.Buffer = buffers[idx]; writerThread.haveWork.Set(); if (!finishing) { General.Log($"{idx} start reading next portion"); reader.Buffer = buffers[idx]; readerThread.haveWork.Set(); General.Log($"{idx} need both In & Out buffers to be Ready to start next part zippin"); readerThread.notifyDone.WaitOne(); // check if have read anyting if (reader.Buffer.BytesRead <= 0) { //have read all, and all is (being) processed finishing = true; // right place to set the reader free readerThread.Finish(); //readerThread.Dispose(); } } writerThread.notifyDone.WaitOne(); if (finishing) { worker.Finish(); workers[idx].Dispose(); workers[idx] = null; //can clean buffers here as well buffers[idx].Dispose(); buffers[idx] = null; } else { worker.haveWork.Set(); } //cause rotating, and output shall be in-order if (++idx >= workers.Length) { idx = 0; } } while (true); General.Log($"{act} finished successfuly."); } catch (Exception exc) { General.Log($"ManageThreads encountered an error {exc.Message} returning to caller."); throw; } finally { CleanUp(buffers, workers); } }