How to check .NET BlockingCollection status and wait for completion?

I have a C # workflow that saves a camera bitmap package to disk using BlockingCollection. It works well, but I need a method that is called from the main application, which blocks execution until all the bitmap images in the queue are saved (see, for example, the end of the message).

The whole class is as follows:

namespace GrabGUI
{
    struct SaveTask
    {
        public string fname;
        public Bitmap bm;
    }

    class ImageWriter
    {
        private BlockingCollection<SaveTask> queue = new BlockingCollection<SaveTask>();

        //resets when read
        public string ErrorsOccurred;
        private Thread writerthread;

        public ImageWriter()
        {
            writerthread = new Thread(new ThreadStart(Writer));
            writerthread.Start();
        }


        public void Stop()
        {
            queue.CompleteAdding();
        }

        public string WaitForIdleAndGetErrors()
        {
            //HOW TO WAIT FOR QUEUE TO GET PROCESSED?

            return ErrorsOccurred;
        }

        public void AddImageToQueue(string filename, Bitmap bmap)
        {
            SaveTask t;
            t.bm=bmap;
            t.fname=filename;
            queue.Add(t);
        }

        void Writer()
        {
            while (queue.IsCompleted==false)
            {
                try
                {
                    SaveTask t = queue.Take();// blocks when the queue is empty
                    SaveBitmap(t.fname, t.bm);
                }
                catch (Exception e)
                {
                    //comes here after called Stop
                    return;
                }
            }
        }


        private void SaveBitmap(string filename,Bitmap m_bitmap)
        {
            //saving code
        }

    }
}

And used from the main application, for example:

ImageWriter w=new ImageWriter();

w.AddImageToQueue(fname,bitmap);//repeat many times
...

//wait until whole queue is completed and get possible errors that occurred
string errors=w.WaitForIdleAndGetErrors();

So the question is how to implement waitlocking WaitForIdleAndGetErrors (). Any suggestions?

+4
source share
3 answers

One very easy way:

public string WaitForIdleAndGetErrors()
{
    while (queue.IsCompleted == false )
    {
       System.Threading.Thread.Current.Sleep(100);
    }

   return ErrorsOccurred;
}

Or use ManualResetEventSlim:

var:

ManualResetEventSlim _mre = new ManualResetEventSlim(false);

public string WaitForIdleAndGetErrors()
{
    if (queue.IsCompleted == false )
    {
       _mre.Wait();
    }

   return ErrorsOccurred;
}

, mre.

_mre.Set();   // this will release any thread waiting.

, Reset() _mre, , Wait() , _mre ( Set())

, , - , .

, BackgroundWorker, Invoke /, .

+4

, . WaitForIdleAndGetErrors . Thread.Join:

    public string WaitForIdleAndGetErrors()
    {
        // Wait for thread to exit
        writerthread.Join();

        return ErrorsOccurred;
    }

Thread.Join . , , .

, , BlockingCollection.GetConsumingEnumerable:

    void Writer()
    {
        foreach (SaveTask t in queue.GetConsumingEnumerable())
        {
            try
            {
                SaveBitmap(t.fname, t.bm);
            }
            catch (Exception e)
            {
                //comes here after called Stop
                return;
            }
        }
    }
+4

, (Thread.Join ) , ManualResetEventSlim :

    ManualResetEventSlim _mre = new ManualResetEventSlim(false);

    public Task<string> WaitForIdleAndGetErrors()
        {
            return Task.Factory.StartNew(() =>
            {
                if (!_queue.IsCompleted)
                {
                    _mre.Wait();
                }
                return ErrorsOccurred;
            });
        }

, , () , , , . :

// Calling Thread
...
imageWriter.WaitForIdleAndGetErrors.Wait(myDesiredWaitLimit);
...
0

Source: https://habr.com/ru/post/1535572/


All Articles