Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have a C# worker thread that saves batch of camera bitmaps to disc in by using BlockingCollection. It works nicely but I need a method to be called from main app that blocks execution until all queued bitmaps are saved (see end of message for example).

The whole class looks like:

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 is used from main app like:

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 the blocking wait to WaitForIdleAndGetErrors(). Any suggestions?

like image 325
TeroK Avatar asked Feb 14 '23 06:02

TeroK


1 Answers

One very simple way here:

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

   return ErrorsOccurred;
}

Or use a ManualResetEventSlim:

Declare new instance var:

ManualResetEventSlim _mre = new ManualResetEventSlim(false);

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

   return ErrorsOccurred;
}

Then when your queue is complete signal the mre.

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

Finally, you need to Reset() the _mre when an item is added for processing, this will cause any Wait() to block until the _mre is signaled (via Set())

Things to consider

If you call this with the UI Thread then all UI interaction will appear to be frozen, you'd be better off using a Timer to poll or something similar otherwise you will have a bad UI experience.

However you could fire this whole thing off using a BackgroundWorker and then Invoke a method/event that the UI thread will process upon completion.

like image 147
T McKeown Avatar answered Feb 15 '23 20:02

T McKeown