static int MULTIPLEXOR_TIMEOUT = -1; // -1 is infinite

        public static void ExecuteSimpleLoadBalencedPipelineOperation(string inputDirectory, string BackgroundFilePath, string outputdir, CancellationToken token)
        {
            var buffer1 = new BlockingCollection <BitmapWithFilePathAndSeq>(BUFFER_SIZE);

            var buffer2ForNormalTask1    = new BlockingCollection <BitmapWithFilePathAndSeq>(BUFFER_SIZE);
            var buffer2ForThumbnailTask1 = new BlockingCollection <BitmapWithFilePathAndSeq>(BUFFER_SIZE);
            var buffer2ForNormalTask2    = new BlockingCollection <BitmapWithFilePathAndSeq>(BUFFER_SIZE);
            var buffer2ForThumbnailTask2 = new BlockingCollection <BitmapWithFilePathAndSeq>(BUFFER_SIZE);

            var buffer3ForNormal    = new BlockingCollection <BitmapWithFilePathAndSeq>(BUFFER_SIZE);
            var buffer3ForThumbnail = new BlockingCollection <BitmapWithFilePathAndSeq>(BUFFER_SIZE);

            var buffer4 = new BlockingCollection <BitmapWithFilePathAndSeq>(BUFFER_SIZE);

            Bitmap background_bm = ImageProcessor.LoadFileAsImage(BackgroundFilePath);

            using (CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(token))
            {
                var f = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None);

                // FIRST TASK
                var stage1 = f.StartNew(() => LoadImages(inputDirectory, buffer1, cts));

                // SECOND TASK
                var stage2Task1 = f.StartNew(() => RemoveBackground(buffer1, (Bitmap)background_bm.Clone(), cts, buffer2ForNormalTask1, buffer2ForThumbnailTask1));
                var stage2Task2 = f.StartNew(() => RemoveBackground(buffer1, (Bitmap)background_bm.Clone(), cts, buffer2ForNormalTask2, buffer2ForThumbnailTask2));

                //MULTIPLEXER
                var multiplexerNormal    = f.StartNew(() => Multiplexer(buffer3ForNormal, cts, buffer2ForNormalTask1, buffer2ForNormalTask2));
                var multiplexerThumbnail = f.StartNew(() => Multiplexer(buffer3ForThumbnail, cts, buffer2ForThumbnailTask1, buffer2ForThumbnailTask2));

                // THIRD TASKs
                var stage3Normal    = f.StartNew(() => SaveBitmap(buffer3ForNormal, outputdir, cts));
                var stage3Thumbnail = f.StartNew(() => CreateThumbnail(buffer3ForThumbnail, buffer4, cts));

                // FOURTH TASK
                var stage4 = f.StartNew(() => SaveThumbnailBitmap(buffer4, outputdir, cts));

                try
                {
                    Task.WaitAll(stage1, stage2Task1, stage2Task2, multiplexerNormal, multiplexerThumbnail, stage3Normal, stage3Thumbnail, stage4);
                }
                catch (Exception ex)
                {
                    if (ex is AggregateException ae) // Unwrap aggregate exception.
                    {
                        ae.Handle((ie) =>
                        {
                            throw ie;
                        });
                    }
                    throw ex;
                }
            }
        }
 /// <summary>
 /// Executes all operations sequentially.
 /// </summary>
 private static void ExecuteSequentialAllOperation()
 {
     foreach (string filePath in Directory.GetFiles(InputDirectory))
     {
         if (Path.GetExtension(filePath) == ".bmp")
         {
             Bitmap background_bm = ImageProcessor.LoadFileAsImage(BackgroundFilePath);
             ExecuteSequentialOperation(filePath, background_bm);
         }
     }
 }
        /// <summary>
        /// Executes a image processing operation.
        /// </summary>
        /// <param name="filePath">Path to the file image to process.</param>
        /// <param name="background_bm">The background image.</param>
        private static void ExecuteSequentialOperation(string filePath, Bitmap background_bm)
        {
            Bitmap target_bm = ImageProcessor.LoadFileAsImage(filePath);

            target_bm = ImageProcessor.RemoveBackground(target_bm, background_bm);
            Bitmap target_thumb_bm = ImageProcessor.ResizeToThumbnail(target_bm);

            string output       = OutputDirectory + Path.DirectorySeparatorChar + Path.GetFileName(filePath);
            string output_thumb = OutputDirectory + Path.DirectorySeparatorChar + Path.GetFileNameWithoutExtension(filePath) + "_thumbnail" + Path.GetExtension(filePath);

            ImageProcessor.SaveBitmapToFile(target_bm, output);
            ImageProcessor.SaveBitmapToFile(target_thumb_bm, output_thumb);
        }
        private static void LoadImages(string InputDirectory, BlockingCollection <BitmapWithFilePathAndSeq> outputQueue, CancellationTokenSource cts)
        {
            int SeqIdNext           = 1;
            CancellationToken token = cts.Token;

            try
            {
                foreach (string filePath in Directory.GetFiles(InputDirectory))
                {
                    if (token.IsCancellationRequested)
                    {
                        break;
                    }

                    if (Path.GetExtension(filePath) == ".bmp")
                    {
                        Bitmap bm = ImageProcessor.LoadFileAsImage(filePath);

                        var outputObj = new BitmapWithFilePathAndSeq()
                        {
                            FilePath = filePath,
                            Image    = bm,
                            SeqId    = SeqIdNext++
                        };
                        outputQueue.Add(outputObj, token);
                    }
                }
            }
            catch (Exception ex)
            {
                if (!(ex is OperationCanceledException))
                {
                    cts.Cancel();
                    throw;
                }
            }
            finally
            {
                outputQueue.CompleteAdding();
            }
        }
        public static void ExecuteTestPipelineStepOperation(string inputDirectory, string BackgroundFilePath, string outputdir, CancellationToken token)
        {
            var buffer1 = new BlockingCollection <BitmapWithFilePathAndSeq>(BUFFER_SIZE);

            var buffer2ForNormalTask1    = new BlockingCollection <BitmapWithFilePathAndSeq>(BUFFER_SIZE);
            var buffer2ForThumbnailTask1 = new BlockingCollection <BitmapWithFilePathAndSeq>(BUFFER_SIZE);
            var buffer2ForNormalTask2    = new BlockingCollection <BitmapWithFilePathAndSeq>(BUFFER_SIZE);
            var buffer2ForThumbnailTask2 = new BlockingCollection <BitmapWithFilePathAndSeq>(BUFFER_SIZE);

            var buffer3ForNormal    = new BlockingCollection <BitmapWithFilePathAndSeq>(BUFFER_SIZE);
            var buffer3ForThumbnail = new BlockingCollection <BitmapWithFilePathAndSeq>(BUFFER_SIZE);

            var buffer4 = new BlockingCollection <BitmapWithFilePathAndSeq>(BUFFER_SIZE);

            Bitmap background_bm = ImageProcessor.LoadFileAsImage(BackgroundFilePath);

            using (CancellationTokenSource cts = CancellationTokenSource.CreateLinkedTokenSource(token))
            {
                var f = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None);
                List <TaskPipelineStep <BitmapWithFilePathAndSeq> > pipelineSteps = new List <TaskPipelineStep <BitmapWithFilePathAndSeq> >();

                // FIRST TASK
                var pipelineStep1Task = new PipeLineStep <BitmapWithFilePathAndSeq, BitmapWithFilePathAndSeq>(
                    null,
                    (
                        BlockingCollection <BitmapWithFilePathAndSeq> inputQ,
                        BlockingCollection <BitmapWithFilePathAndSeq> outputQ,
                        CancellationToken suspend,
                        CancellationTokenSource cancel
                    ) => LoadImages(inputDirectory, outputQ, cancel),
                    cts,
                    buffer1
                    ).Start();

                // SECOND TASK
                var pipelineStep2 = new PipeLineStep <BitmapWithFilePathAndSeq, BitmapWithFilePathAndSeq>(
                    buffer1,
                    (
                        BlockingCollection <BitmapWithFilePathAndSeq> inputQ,
                        BlockingCollection <BitmapWithFilePathAndSeq> outputQ,
                        CancellationToken suspend,
                        CancellationTokenSource cancel
                    ) => RemoveBackground(inputQ, background_bm, cts, suspend, outputQ),
                    cts,
                    buffer3ForThumbnail,
                    buffer3ForNormal
                    );
                Task pipelineStep2Task = pipelineStep2.Start();
                pipelineSteps.Add(new TaskPipelineStep <BitmapWithFilePathAndSeq>()
                {
                    Name         = "Step 2",
                    PipelineStep = pipelineStep2,
                    Tasks        = new List <Task>()
                    {
                        pipelineStep2Task, pipelineStep2.MultiplexorTask
                    },
                    Queue = buffer1,
                });

                // THIRD TASKs
                var pipelineStep3 = new PipeLineStep <BitmapWithFilePathAndSeq, BitmapWithFilePathAndSeq>(
                    buffer3ForThumbnail,
                    (
                        BlockingCollection <BitmapWithFilePathAndSeq> inputQ,
                        BlockingCollection <BitmapWithFilePathAndSeq> outputQ,
                        CancellationToken suspend,
                        CancellationTokenSource cancel
                    ) => CreateThumbnail(inputQ, outputQ, cancel),
                    cts,
                    buffer4
                    );
                Task pipelineStep3Task = pipelineStep3.Start();
                pipelineSteps.Add(new TaskPipelineStep <BitmapWithFilePathAndSeq>()
                {
                    Name         = "Step 3",
                    PipelineStep = pipelineStep3,
                    Tasks        = new List <Task>()
                    {
                        pipelineStep3Task, pipelineStep3.MultiplexorTask
                    },
                    Queue = buffer3ForThumbnail,
                });

                var stage3Normal = f.StartNew(() => SaveBitmap(buffer3ForNormal, outputdir, cts));

                // FOURTH TASK
                var stage4 = f.StartNew(() => SaveThumbnailBitmap(buffer4, outputdir, cts));

                try
                {
                    DistributeAvailableTasksAndAwaitPipelineCompletion(new List <Task>()
                    {
                        pipelineStep1Task, stage3Normal, stage4
                    }, pipelineSteps);
                }
                catch (Exception ex)
                {
                    if (ex is AggregateException ae) // Unwrap aggregate exception.
                    {
                        ae.Handle((ie) =>
                        {
                            throw ie;
                        });
                    }
                    throw ex;
                }
            }
        }