Larry Osterman writes about a real error found in Microsoft’s code, the offending code is
static DWORD WINAPI _PlayBeep(__in void* pv)
{
UNREFERENCED_PARAMETER(pv);
PlaySound(L".Default"NULL, SND_SYNC | SND_ALIAS);
return 0;
}
LRESULT WndProc(...)
{
:
:
case WM_KEYDOWN:
if (!_AcceptInputKeys(wParam, lParam))
{
QueueUserWorkItem(_PlayBeep, NULL, 0);
}
break;
}
and Larry asks:
Given the simplicity of the code
above, to get the answer right, it’s
not enough to say what’s wrong with
the code (the problem should be
blindingly obvious). You also need to
be able to explain why this is so bad
(in other words, what breaks when you
do this).
The best answer is terse in the comments is not enough,
David’s VERY close to what’s going
wrong – now think about the context of
the application.
Can someone please explain fully what’s happening when this code runs?
Read the answer page, it’s got a very detailed explanation
http://blogs.msdn.com/b/larryosterman/archive/2009/06/29/what-s-wrong-with-this-code-part-26-the-answer.aspx
Basically, don’t use
QueueUserWorkItemfor long-running work items because this can cause thread exhaustion in your process, or even deadlock in a very hard to debug way if you wait for work items to complete on a (necessarily) finite-sized thread pool. Same goes for the .Net equivalent of this API ThreadPool.QueueUserWorkItem btw.In this specific case, the workitem trigger (“press the down key”) and the resulting thread workitem (“sound a sync beep”) are very unbalanced, so that if user holds down or repeatedly hits his/her down key, the process will quickly hit fatal issues.