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?
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())
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With