If MessageBox()/related are synchronous, why doesn't my message loop freeze?
blocking, c++, multithreading, synchronous, winapi
Solution
The `MessageBox()` and similar Windows API functions are not blocking the execution, like an IO operation or mutexing would do. The `MessageBox()` function creates a dialog box usually with an OK button - so you'd expect automatic handling of the window messages related to the message box. This is implemented with its own message loop: no new thread is created, but your application remains responsive, because selected messages (like for painting) are handled calling recursively your `WndProc()` function, while other messages are not transmitted, because of the modal type of the created window.
`Sleep()` and other functions (when called directly from your `WndProc()` handling a window message) would actually block the execution of your single threaded message loop - no other message would be processed.
Problem
Why is it that if I call a seemingly synchronous Windows function like `MessageBox()` inside of my message loop, the loop itself doesn't freeze as if I called `Sleep()` (or a similar function) instead? To illustrate my point, take the following skeletal `WndProc`: ``` int counter = 0; LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CREATE: SetTimer(hwnd, 1, 1000, NULL); //start a 1 second timer break; case WM_PAINT: // paint/display counter variable onto window break; case WM_TIMER: //occurs every second counter++; InvalidateRect(hwnd, NULL, TRUE); //force window to repaint itself break; case WM_LBUTTONDOWN: //someone clicks the window MessageBox(hwnd, "", "", 0); MessageBeep(MB_OK); //play a sound after MessageBox returns break; //default .... } return 0; } ``` In the above example, the program's main function is to run a timer and display the counter's value every second. However, if the user clicks on our window, the program displays a message box and then beeps after the box is closed. Here's where it gets interesting: we can tell `MessageBox()` is a synchronous function because `MessageBeep()` doesn't execute until the message box is closed. However, the timer keeps running, and the window is repainted every second even while the message box is displayed. So while `MessageBox()` is apparently a blocking function call, other messages (`WM_TIMER`/`WM_PAINT`) can still be processed. That's fine, except if I substitute MessageBox for another blocking call like `Sleep()` ``` case WM_LBUTTONDOWN: Sleep(10000); //wait 10 seconds MessageBeep(MB_OK); break; ``` This blocks my application entirely, and no message processing occurs for the 10 seconds (`WM_TIMER`/`WM_PAINT` aren't processed, the counter doesn't update, program 'freezes', etc). So why is it that `MessageBox()` allows message processing to continue while `Sleep()` doesn't? Given that my application is single-threaded, what is it that `MessageBox()` does to allow this functionality? Does the system 'replicate' my application thread, so that way it can finish the `WM_LBUTTONDOWN` code once `MessageBox()` is done, while still allowing the original thread to process other messages in the interim? (that was my uneducated guess) Thanks in advance