Note that there are some explanatory texts on larger screens.

plurals
  1. POPostMessage messages to an application seem to get lost when the app's main thread is busy
    primarykey
    data
    text
    <p>I'm writing a multithread program which uses messaging to communicate between threads. I'm using Embarcadero RAD Studio C++ Builder 2010. These messages are sent using PostMessage to Application's handle and then are processed by a function (code from the main form's constructor: <code>Application-&gt;OnMessage = CatchMessage;</code>) where <code>CatchMessage</code> is a method of main form. That CatchMessage contains some code to be executed (like waking up another thread, see the code below).</p> <p>Here goes my issue with it. Every time you grab a window to move it, the content of the window gets "frozen" until you let go of the window or start moving it. Apparently, the main thread of the application gets hung up; AND all the messages that I send during this period of time are simply "lost" - the code in them is never executed.</p> <p>Below goes my code (there's a main thread, thread for Drawing (from pixel array to an internal bitmap) and thread for Rendering (filling the pixel array). They are synchronized in the following way: Renderer makes a new frame in loop, triggers a boolean indicating that there's a fresh frame and, if the Drawer finished drawing the previous frame, sends a message that swaps two buffers (necessary thing in the context of my application) and awakens the sleeping Drawer; then waits until there's a confirmation that the buffers are swapped; and if the Drawer is still busy with the previous frame, Renderer just starts making yet another frame. The Drawer, when awakened, states that it's busy, draws the frame, sends a message that triggers a memcpy to the Form's Canvas (thread-safe because it's done from main thread), states that it's ready and goes to sleep (drawing in 99% of cases happens faster than Rendering so this measure is to save some CPU time in this thread).</p> <p>The issue is that when I grab a window to move it, the moving image on the form stops. Sending a pause signal to all threads (not stopping them, just triggering a boolean that they check on each cycle) makes one of them exit, but another one keeps going forever (I see in the Task Manager that one core is 100% busy). I've narrowed this issue down to message sending: when the message from Renderer gets "lost" and the code of its handler is never executed, two things happen: 1) Drawer thread is never awaken; 2) Render thread is stuck in an infinite loop waiting for a confirmation of buffer swapping.</p> <p>The code:</p> <pre><code>__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { Application-&gt;OnMessage = CatchMessage; } bool TimeToStop; DWORD WINAPI DrawLoop(LPVOID params) { while(!TimeToStop) { GE.DrawerReady = 0; GE.FrameCounter++; GE.DrawToBitmap(); PostMessage(Application-&gt;Handle, BITMAP_READY, 0, 0); GE.DrawerReady = 1; SuspendThread(DrawLoopHandle); } return 0; } DWORD WINAPI PseudoRenderLoop(LPVOID params) { while(!TimeToStop) { GE.GenerateDemoFrame(); if(GE.DrawerReady) { GE.BuffersAreSwitched = 0; SendMessage(Application-&gt;Handle, RENDER_READY, 0, 0); while(!GE.BuffersAreSwitched){} } } return 0; } void __fastcall TForm1::Button1Click(TObject *Sender) // "Go / Pause" button { if(TimeToStop == 1) { TimeToStop = 0; DrawLoopHandle = CreateThread(NULL, 0, DrawLoop, NULL, 0, NULL); PseudoRenderLoopHandle = CreateThread(NULL, 0, PseudoRenderLoop, NULL, 0, NULL); } else { TimeToStop = 1; } } void __fastcall TForm1::CatchMessage(tagMSG &amp;Msg, bool &amp;Handled) { if(Msg.message == BITMAP_READY) { Form1-&gt;Invalidate(); GE.FrameCounter++; } else { if(Msg.message == RENDER_READY) { GE.SwitchRenderBuffers(); ResumeThread(DrawLoopHandle); GE.BuffersAreSwitched = 1; } } } </code></pre> <p>When the <code>SendMessage(Application-&gt;Handle, RENDER_READY, 0, 0);</code> gets lost because the main thread is busy while I hold the window, the changing of buffers, confirmation of it and awakening of Drawer thread never happen, so the Drawer thread is forever suspended and the Renderer thread is stuck in the loop <code>while(!GE.BuffersAreSwitched){}</code>. A strange thing, though, is when I hit pause, I still see ONE (out of two) threads exit, which is unexpected because when one is suspended and another is in a loop, they both can't reach <code>return 0;</code> code.</p> <p>I'm absolutely sure that this behavior is caused by the messages lost, because when I replaced the communications with some booleans (while(!variable){} instead of SuspendThread, etc) everything started working as intended. My question: how do I make sure that the messages aren't lost when main thread is busy? The solution with booleans still works, but this way the waiting Drawer thread eats up CPU, while it could be Suspended and not do that.</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload