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