Producer/Consumer example

  • Thread starter Thread starter Ryan Taylor
  • Start date Start date
R

Ryan Taylor

I am building an application where data is coming in from a hardware deveice
attached to the serial port. The data needs to be queued ASAP. I figured a
could create a custom class containing this data and store it in an
ArrayList for future processing. I want to process this data continually so
that is could be preserved in case of a system failure. I was thinking of
implement a producer/consumer relationship using threading. However, I
haven't been able to find an example that explains things in a way that I
can digest. Does anyone know of any good resources for developing
producer/consumer systems with C# and Threading?

Thanks.
Ryan.
 
Ryan Taylor said:
I am building an application where data is coming in from a hardware deveice
attached to the serial port. The data needs to be queued ASAP. I figured a
could create a custom class containing this data and store it in an
ArrayList for future processing. I want to process this data continually so
that is could be preserved in case of a system failure. I was thinking of
implement a producer/consumer relationship using threading. However, I
haven't been able to find an example that explains things in a way that I
can digest. Does anyone know of any good resources for developing
producer/consumer systems with C# and Threading?

See
http://www.pobox.com/skeet/csharp/threads/deadlocks.shtml

(about half way down).
 
I get the following error when naviagating to that url.

Not Found
The requested URL /skeet/csharp/threads/deadlocks.shtml was not found on
this server.
Apache/1.3.33 Server at www.pobox.com Port 80
 
How about writing a Win32 Service which reads from the device and puts the
data on a MSMQ queue and then the other piece of the application runs either
as another service or interactively and processes the data? You could even
do the processing on a different machine if you want to. I have designed a
couple of solutions like this and it's really flexible.

Olav
 
Excellent examples. Thank you very much. I have managed to get a simple
shared counter working. One thread tries to increment the counter, the other
tries to decrement the counter. All while updating the GUI through
delegates.

One thing I remain unclear on is the ManualResetEvent variables. I've been
able (I think) to implement these successfully, but I really want to
understand their purpose, when to use them, when not to use them. Why could
I not just use a reference to a boolean variable to stop the thread. I
assume that is because it would not be thread safe. If anyone can explain
this to me that would be most excellent.

Thanks.

// Counter class
public class Counter
{
private readonly object countLock = new object();
private int count = 0;

private ManualResetEvent incStop;
private ManualResetEvent incStopped;

private ManualResetEvent decStop;
private ManualResetEvent decStopped;

private MainForm frm;

public Counter(ManualResetEvent incrementStop, ManualResetEvent
incrementStopped, ManualResetEvent decrementStop, ManualResetEvent
decrementStopped, MainForm form)
{
incStop = incrementStop;
incStopped = incrementStopped;

decStop = decrementStop;
decStopped = decrementStopped;

frm = form;
}

public void Increment(int val, int sleep)
{
while(true)
{
lock(countLock)
{
int tmp = count;
frm.Invoke(frm.AddStringIncrementDelegate, new object[] {"Reading
Value: " + Convert.ToString(tmp)});
frm.Invoke(frm.AddStringDecrementDelegate, new object[] {""});

tmp = tmp + val;
frm.Invoke(frm.AddStringIncrementDelegate, new object[]
{"Incremented by: " + Convert.ToString(val)});
frm.Invoke(frm.AddStringDecrementDelegate, new object[] {""});

count = tmp;
frm.Invoke(frm.AddStringIncrementDelegate, new object[] {"Writing
Value: " + Convert.ToString(tmp)});
frm.Invoke(frm.AddStringDecrementDelegate, new object[] {""});

frm.Invoke(frm.SetCurrentCountDelegate, new object[]
{Convert.ToString(count)});

Thread.Sleep(sleep);
if(incStop.WaitOne(0, true))
{
incStopped.Set();
return;
}
}
}

frm.Invoke(frm.IncrementThreadFinishedDelegate, null);
}
}

// Called in the form when the stop thread button is pressed.
private void StopIncrement()
{
if(incrementThread != null && incrementThread.IsAlive) // thread is active
{
// set event "Stop"
incrementStopEvent.Set();

// wait when thread will stop or finish
while(incrementThread.IsAlive)
{
if(WaitHandle.WaitAll((new ManualResetEvent[]
{incrementStoppedEvent}), 100, true))
{
break;
}

Application.DoEvents();
}
}

IncrementThreadFinished(); // set initial state of buttons
}

// counter class initialization
incrementStopEvent = new ManualResetEvent(false);
incrementStoppedEvent = new ManualResetEvent(false);
decrementStopEvent = new ManualResetEvent(false);
decrementStoppedEvent = new ManualResetEvent(false);

counter = new Counter(incrementStopEvent, incrementStoppedEvent,
decrementStopEvent, decrementStoppedEvent, this);
 
Ryan Taylor said:
Excellent examples. Thank you very much. I have managed to get a simple
shared counter working. One thread tries to increment the counter, the other
tries to decrement the counter. All while updating the GUI through
delegates.

One thing I remain unclear on is the ManualResetEvent variables. I've been
able (I think) to implement these successfully, but I really want to
understand their purpose, when to use them, when not to use them. Why could
I not just use a reference to a boolean variable to stop the thread.
I assume that is because it would not be thread safe. If anyone can explain
this to me that would be most excellent.

You can use a boolean variable, but you need some locking to make sure
that the worker thread sees any changes to the value.

See http://www.pobox.com/~skeet/csharp/threads/volatility.shtml for the
reason. (In fact, it uses stopping a thread as an example.)
 
Back
Top