Bitten by Critical Sections
I love Critical Section objects in Windows, they are very useful for lightweight thread locking. But this week, I’ve found an unexpected behaviour.
Normally I use critical sections to make sure multithreaded code does not re-enter, especially if I have operations which must be atomic. Here is some typical code to prevent CallFunction1() ever being called while in the middle of running CallFunction2():
// This is called by a WM_TIMER event.
void onTimer()
{
EnterCriticalSection(crit1);
CallFunction1();
LeaveCriticalSection(crit1);
}
// This is called from a worker thread.
void OtherFunction()
{
EnterCriticalSection(crit1);
CallFunction2();
LeaveCriticalSection(crit1);
}
Now I found that if CallFunction2() happens to do something like launch a message box, the critical section does not lock out CallFunction1() as you would expect. The messagebox will of course run the message pump, the WM_TIMER message will occur and the onTimer() function will run even though the critical section object is locked.
This is because a critical section will only lock out other threads. It will not lock out reentrant calls made from the same thread.
This is mentioned in the MSDN documentation if you dig deep enough but it sure caught me out this week!

Forwarded from Joachim Lührs:
Hi doc T,
nice homepage man.
When i read your article i could not believe this to be true.
So i tried to reproduce what you say you observed – but i couldn’t.
But maybe you have deeper knowledge and could give some other hints ? “This is mentioned in the MSDN documentation if you dig deep enough…” ?
Here’s what i always assumed to be right (and my test seems to prove that again) :
The thread that creates a window (here the WinMain thread) is the only one which can get messages to that window from its queue!
The queue ‘belongs’ to that thread and the window is kinda ‘bound’ to it (CreateWindow(pClassName, …).
So if you post a message into the queue for a ‘bound’ window, like the system does with WM_TIMER, the only thread to get it out is your WinMain thread!
(GetMessage / DispatchMessage / WNDPROC / OnTimer)
The only way to bypass this would be a direct call to WNDPROC or OnTimer from your WorkerThread or some other hack, – but you wouldn’t do this normally.
So i really cant’t imagine any circumstances that result in a proper WM_TIMER handler being called from 2 different threads…….if my assumptions are right ;)
What happens exactly if you call MessageBox from within your worker, which does not serve its message queue, right ? – i dont’ know.
You say “The messagebox will of course run the message pump”.. but i think this is done by somehow bypassing the ordinary message pump and calling the required window painting functions directly (as subroutines within the worker thread)..
see also here:
http://oopweb.com/Assembly/Documents/Win32ASM/Volume/winmsg.htm
am i wrong ?
can you prove your statement ?
regards,
joL
The relevant MSDN documentation is here:
http://msdn.microsoft.com/en-us/library/ms682530(VS.85).aspx
It says “When a thread owns a critical section, it can make additional calls to EnterCriticalSection or TryEnterCriticalSection without blocking its execution.”
This is not the behaviour I expected. I expected any further calls to EnterCriticalSection to be blocked until the original piece of code calls LeaveCriticalSection.
Also understand I am not talking about multi-threaded code here, it is all happening within a single thread.
I don’t think there is any bug in Windows, I just did not understand how Critical Sections work in a single-thread situation. I assumed they would work the same as they do in multi-threaded code.