Esempio n. 1
0
        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);
            }
        }