Joining Threads vs. Monitors

M

Mathias Hasselmann

Hello,

Hope this is the right group for asking this. Didn't see a threading
specific newsgroup here.

I currently expire unexpected dead-locks within some trivial C# code.
Now I wonder if it is expected behaviour, that monitors do no wake up,
when the thread previously owning the monitor class class Join on the
thread waiting for the monitor? Simplified the code I have looks like this:

class DeadLock
{
object mutex = new object();
Thread thread = null;

void Start()
{
thread = new Thread(Worker);
thread.Start();
}

void Cancel()
{
lock(mutex) {
/* ... */
}

thread.Join();
}

void Worker()
{
/* ... */

lock(mutex) {
/* ... */
}
}
}

When calling Cancel before Worker reaches its critical section I
observe, the following:

- Cancel acquires the monitor and enters its section
- shortly later Worker tries to get the same monitor and blocks
- Cancel releases the monitor and calls waits for Worker to terminate
- Worker never gets be monitor, if I do not manually kill Cancel

I really do not understand, what causes this dead-lock in .NET 2.0.

Thanks,
Mathias Hasselmann
 
J

Jon Shemitz

Mathias said:
I currently expire unexpected dead-locks within some trivial C# code.
Now I wonder if it is expected behaviour, that monitors do no wake up,
when the thread previously owning the monitor class class Join on the
thread waiting for the monitor? Simplified the code I have looks like this:

Lock and Join should not affect each other.
class DeadLock
{
object mutex = new object();
Thread thread = null;

void Start()
{
thread = new Thread(Worker);
thread.Start();
}

void Cancel()
{
lock(mutex) { /* ... */ }
thread.Join();
}

void Worker()
{
/* ... */
lock(mutex) { /* ... */ }
}
}

When calling Cancel before Worker reaches its critical section I
observe, the following:

- Cancel acquires the monitor and enters its section
- shortly later Worker tries to get the same monitor and blocks
- Cancel releases the monitor and calls waits for Worker to terminate
- Worker never gets be monitor, if I do not manually kill Cancel

I really do not understand, what causes this dead-lock in .NET 2.0.

As shown here, this code should work. My guess would be that whatever
Cancel is doing while it has the mutex locked is causing Worker to
hang before it gets to the lock statement.

Fwiw, technically this isn't deadlock: that's when one thread locks A
then B, and another locks B then A. The first thread has A locked, but
can't lock B because the other thread has it locked; the second thread
has B locked, but can't lock A because the first thread has it locked
 
M

Mathias Hasselmann

Lock and Join should not affect each other.

Hmm. Hoped someone would tell me "You are trying something completely
stupid. Do/read this and that. Then it will work". Well, appears like I
have to continue reducing the code for getting a compilable minimal
example of my problem on monday. Hopefully it's really just me doing a
stupid mistake.

Ciao
Mathias
 
M

Mathias Hasselmann

Ok, problem found, left out an important detail of my Start() method.
Where I've written:

void Start()
{
thread = new Thread(Worker);
thread.Start();
}

I really had something like:

void Start()
{
lock(mutex) {
Cancel();
thread = new Thread(Worker);
thread.Start();
}
}


Moving Cancel() out of the synchronized section resolves the lock, which
in fact really was a dead-lock - just didn't find the other monitor that
quickly. Just have to figure out for myself now, if that move doesn't
introduce a race-condition...

To find such issues quicker next time I wonder if .NET provides
utilities like ThreadMXBean#findMonitorDeadlockedThreads()[1], which are
quite helpful for finding monitor dead-locks?

Ciao,
Mathias

1:
http://java.sun.com/j2se/1.5.0/docs...eadMXBean.html#findMonitorDeadlockedThreads()
 
J

Jon Skeet [C# MVP]

To find such issues quicker next time I wonder if .NET provides
utilities like ThreadMXBean#findMonitorDeadlockedThreads()[1], which are
quite helpful for finding monitor dead-locks?

Not that I'm aware of, but I have an OrderedLock class you might like
to look at:
http://www.pobox.com/~skeet/csharp/miscutil/usage/locking.html
It wouldn't have helped in this particular case, but it might in
others. (And actually you could have hit Break in the debugger and seen
which thread owned the lock.)
 

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