Tuesday, December 11, 2007

What's wrong with Monitor::Enter()

Suppose we have the following variable we'd like to set as a state and we'd like to make it thread safe (at most one thread is allowed to access the variable):

bool workQueued;

Now if we write something like this, it's not gonna work:

Monitor::Enter(__box(workQueued));
try
{
workQueued = true;
}
__finally
{
Monitor::Exit(__box(workQueued));
}

Why it will not work? The problem is, after workQueued is boxed, the value is not store anywhere. So the second thread reaches here will execute Enter statement with another object value.

To make it work as desired, we need to create a object whose only purpose is to act like a lock:

Object* lock;

Then, we feed this object to Enter and Exit method:

Monitor::Enter(lock);
try
{
workQueued = true;
}
__finally
{
Monitor::Exit(lock);
}

1 comment:

Xiaoguang said...

The following is from MSDN:

Use Monitor to lock objects (that is, reference types), not value types. When you pass a value type variable to Enter, it is boxed as an object. If you pass the same variable to Enter again, it is boxed as a separate object, and the thread does not block. The code that Monitor is supposedly protecting is not protected. Furthermore, when you pass the variable to Exit, still another separate object is created. Because the object passed to Exit is different from the object passed to Enter, Monitor throws SynchronizationLockException.