Request review of this simple threading code

S

sklett

In the past I've had problems with using threads and getting all kinds of
weird bugs.
I've been reading over Jon Skeet's GREAT website about threading and have
tried to apply some of what I learned. There is almost too much information
there for me, I had a hard time deciding what method or design to choose.

I hoped that I could post this skeleton class for a quick review to make
sure I'm on the right track. If you have a minute, I would appreciate your
comments.

Code:
public class CalibrateDAQViewPresenter :
FunctionalTestModulePresenter<ICalibrateDAQView>
{
private bool _stopping = false;
private bool _stopped = false;
private static readonly object _lockObject = new object();

protected override void Dispose(bool disposing)
{
// let the polling thread exit
lock (_lockObject)
{
_stopping = false;
while (_stopped == false) ;
}
base.Dispose(disposing);
}

public void OnViewReady()
{
_startReadingData();
}

private void _startReadingData()
{
_stopped = false;
_stopping = false;
ThreadPool.QueueUserWorkItem(
delegate
{
_dataPoller();
}
);
}

private void _dataPoller()
{
while(true)
{
lock(_lockObject)
{
if(_stopping)
{
_stopped = true;
return;
}
// do stuff and update view
}

Thread.Sleep(100);
}
}
}


Thanks for reading!
 
A

Adam Clauss

Your code will deadlock upon Dispose. Dispose locks on _lockObject, but
does not release that lock until the thread has stopped. The thread on the
otherhand, requires that same lock in order to stop.
 
A

Adam Clauss

Adam Clauss said:
Your code will deadlock upon Dispose. Dispose locks on _lockObject, but
does not release that lock until the thread has stopped. The thread on
the otherhand, requires that same lock in order to stop.

One solution to this - get rid of the stopped flag.
In Dispose, replace the while loop (waiting on stopped) with a call to:
Monitor.Wait(_lockObject)

That will actually release the lock (allowing the thread to acquire it).
Then, in _dataPoller(), replace the:
_stopped = true;
with a call to:
Monitor.Pulse(_lockObject);

Note: this assumes you are not elsewhere using the _stopped flag.
Consideration may have to be added if other's need this as well.
 
M

Marc Gravell

a: What bugs / errors? This doesn't actually demonstrate anything

b: you're using a static lock at the instance level, so sharing a lock
between all instances; probably not what you wanted

c: if this is talking to a WinForm UI you will need to .Invoke/.BeginInvoke
to the UI to get the UI updates to work

d: while (_stopped == false) ;

This might never exit, as _stopped isn't volatile, so it will probably be
cached in a register; secondly, it is hugely intensive; personally I'd do
something more like the following:

lock(_lockObject) {
while(!_stopped) {
Monitor.Wait(_lockObject);
}
}

And "_stopped = true;" would become:
_stopped = true;
Monitor.Pulse(_lockObject);

Marc
 
M

Marc Gravell

Oh, and re the subject "of this simple threading code"... I'm not sure that
such exists in this universe ;-p
 
S

sklett

Thank you for the help, Adam. I see the problems with the code and am
reworking it now to take your suggestions into consideration. I think I
might move the "thread stopping" logic out of the dispose method and handle
it elsewhere, possibly the Closing event.

thanks again,
Steve
 
S

sklett

Thanks for the tips Marc.

You and Adam have suggested similar solutions, that's always a good thing
;0)

Have a good one,
Steve
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top