Holding a critical section during SendMessage
Can you spot the defect with the following code?
EnterCriticalSection(&cs);SendMessage(hwnd, WM_MYMESSAGE, 0, 0);LeaveCriticalSection(&cs); |
The problem is that the SendMessage() is a blocking call, and Windows can do many things from within this call. This creates a situation that is highly prone to deadlocking.
In the best case scenario, the application will remain responsive but its performance will suffer. The best case is when the target HWND is owned by the calling thread and Windows does not perform any additional message dispatching. In that case, the WNDPROC is invoked and it is up to the handler to determine how long the call will take. All other threads that attempt to acquire the critical section become blocked and application performance suffers.
In the worst case scenario, a deadlock will happen. If the target HWND is on another thread, the call will block until the other thread pumps its message queue and handles the message. However, the other thread may be blocked from pumping its message queue if it is trying to acquire the same critical section.
That simple code above may be an obvious deadlock situation. The situation that is less obvious and more frequently leads to hangs is when you are calling into third party code and are unsure about its implementation details. For example, the following code may be prone to deadlocking without being so obvious:
EnterCriticalSection(&cs);pThirdPartyObject->InvokeFunction();LeaveCriticalSection(&cs); |
The third party code may call something like SendMessage in its implementation, which could lead to a deadlock.
The lesson to learn is: Be careful about what you do while you are holding a synchronization primitive such as a critical section. Minimize the amount of code between the acquire and release.