multithreading: event driven vs message driven - windows

Is there a difference in performance when multi-threading developed with win32 event objects (CreateEvent) or with thread window message queue. Both should use some kind of WaitFor... calls.
My own code almost completely based on event, but maybe I lose something when don't use messages.

If you are worried about the performance difference between thread messages, and kernel events, then you should probably not use thread messages.
Win32 thread message queues are a mechanism developed originally for Windows 16 - when there were no threads. They've grown to handle Win32's threading model, but under the covers they are rather complex beasts.
This has pro's and con's. The cons are, quite simply, that they are slower, and have a lot more limits, than other forms of inter thread synchronization and comms. For starters, because lots of pieces of windows code (MessageBox, DoDragDrop etc) implement modal message loops - there are a lot of times when thread messages can be lost. Its important not to use those APIs from threads that are meant to be receiving thread messages.**1* There are also limits to the size of a message queue before it starts to drop messages, and the thread messaging APIs (GetMessage) do not cause the thread to enter an alertable state (so you cannot use QueueUserAPC).
The pro' for thread messages are - as long as their limits are respected - they are a very reliable pre-made wheel that serializes calls to a thread. If you find yourself implementing a queueing mechanism for a non UI worker thread, why re-invent a well tested wheel - use the pre-built message queue.
**1* This includes most implementations of debugging macro's like ASSERT that will pop up a message box.

Related

Synchronous vs Asynchronous socket reads

Most example apps I come across for receiving data are using async calls. For instance, c++ examples use boost asio services to bind message handlers to callbacks. But what about an app that only needs to listen to data from a single socket and process the messages in order? Would it be faster to have a loop that polls/recv's from the socket and calls the handler without using a callback (assume main and logging threads are separate)? Or is there no performance difference (assume messages are coming in as fast as the network card and kernel can handle them)?
There are many intricacies I don't know such as the impact of callbacks to performance due to things like branch prediction. Or if there will be a performance penalty of the callbacks call a different thread to do the processing. Curious to hear some thoughts, experiences, dialog on this subject to save myself from attempting both implementations to discover the answer.

Is it OK for a text editor to pass each keypress from one thread to another?

I'm implementing a Win32 Console text editor that has an internal message queue for passing around information about which areas to redraw, messages to/from plugins, etc. I prefer it to be single-threaded by default (if there's nothing happening that requires additional threads). I'm considering 2 message queue implementation strategies:
Use general-purpose queue and Win32 Event, so I can use WaitForMultipleObjectsEx to wait for internal messages and user input simultaneously, passing both console input handle and Event handle. In this case, text editor can live entirely within a single thread.
Use I/O Completion Port. In this case, text editor will need at least two threads, one of them calling GetQueuedCompletionStatus to get messages, and another reading user input and sending it to queue via PostQueuedCompletionStatus. The reason it that console input handle cannot be overlapped and WaitFor* functions don't accept Completion Port as a waitable handle, so it's not possible to wait on them simultaneously. Just like in the first setup, both threads don't waste CPU time when there's no input or events, but each keypress has to be passed from one thread to another via IOCP.
Which design is overall better?
Is performance and latency drawback from passing each keypress via IOCP significant for a text editor?
Performance and latency of IOCP is fine for your purpose. I wouldn’t however translate each key press into PostQueuedCompletionStatus. I’d rather PostQueuedCompletionStatus to enqueue multiple keypresses at once, whatever count you get from ReadConsoleInput.
I think performance difference is minimal, either one can be faster depending on the environment. And WaitForMultipleObjects is much easier to implement.
P.S. You sure you need message queue at all? Why don’t you process these redraw requests / plugin messages in whichever thread fired those, using e.g. critical section to guard (console output + your shared state)? If your congestion is low, like 100Hz messages + 15Hz keypresses, and you’ll process them fast, this will get you even lower latency than IOCP or any other queues: with low congestion or brief locking, critical sections don’t even switch to kernel for lock/unlock. This will also simplify design, your main thread will sleep on blocking ReadConsoleInput() call, no need to WaitFor.. before that.

Why will STA thread "leak small amounts of memory" if it fails to dispatch Windows messages?

After carefully reading this KB article I noticed an interesting statement there. The article says that if I have an STA thread and that thread doesn't dispatch Windows messages then that thread
will be unable to receive COM events form a COM server
can cause message broadcasters to hang (and thus sometimes cause a deadlock)
surprisingly... will leak small amounts of memory
While the first two statements are rather reasonable - Windows messages are used for dispatching COM calls to objects in single-threaded apartments - I don't get the third one at all.
Why exactly will a thread "leak small amounts of memory" if it doesn't dispatch Windows messages?
I would imagine because that a struct is allocated, and posted with the message.
If the message is not processed, the struct containing the message parameters will not be freed.
The messages that you're failing to dispatch - they must be queued up somewhere, waiting for that fateful moment at which you'll finally start dispatching them. That queue is going to use some memory.

how to create a blocking function

I have a thread that needs to dispatch a message (a simulated mouse event that it sends using SendInput) as soon as it's generated. I want this to happen in a loop where there is no sleep; adding any sleep hurts performance as I basically want the events to go in to the event loop immediately once they have been generated. Of course I also don't want the loop in the consumer thread to hog all the cpu so I can't just keep it running, although this gives me good performance.
As far as I understand this, the task is to make the consuming thread to wait for something that signals that the producing thread has provided something to dispatch (?) but how to best do this? I think I need something like two mutexes if I want to make the two threads mutually exclusive; consumer waits for the producer and the producer continues as soon as the consumer resumes running? Didn't really get this working so far and I'm really not sure how to best do this; CriticalSections vs. mutexes, something entirely different?
The reason I don't want to call SendInput from the producer thread is that that thread (the 'main thread'?) actually runs in response to a mouse move message, intercepted by a mouse hook, and sending more mouse messages from that thread didn't allow the thread to finnish before the simulated mouse move event was processed, messing things for me. As I suspected, moving the SendInput call to another thread so that the original thread could finish out of the way fixed the problem but now I need to make the consumer more responsive; mouse messages keep coming at a good pace I suppose since just a 1 ms Sleep made the loop too slow and message processing started lagging; all works well if I have no sleep.
Thanks.
Sounds like you want to use win32 event objects instead of mutexes or critical sections. See the docs here. The event functions allow a thread to wait on a condition that can be signaled from another thread.
Windows threads support message queues - usually used for windows messages but completely usable for messaging between worker threads. PostThreadMessage can be used in the Hook Proc to post messages to another thread for processing.
The worker thread can do a normal GetMessage loop to extract messages to process - rather than passing them on to DispatchMessage as you would in a UI thread you simply check the HWND is NULL in the message structure indicating its a thread message, then process the message yourself. In the case of potential message flooding PeekMessage can be used to cull any outstanding messages from the queue.

Window moving and resizing interferes with MsgWaitForMultipleObjects

I have an application that message-loops using MsgWaitForMultipleObjects to catch additional events while pumping ui messages. It seems that as soon as a window is being moved or resized, DefWindowProc begins it's own message loop until the mouse is being released. This situation prevents from the outer loop to catch the additional messages in the meantime.
I'd hate to multi-thread the application just because of this. Is there any other way to solve it?
MsgWaitForMultipleObjects has very few uses in a traditional multi threaded program. It has some use in Games - where traditional non client frame elements are omitted and APIs like "MessageBox" and "DoDragDrop" are avoided...
Usually it finds its best use in "UI worker" threads that don't host visible windows, but use the message queue as an inter thread messaging system and also need to wait on kernel handles.
In your case, making a second thread does not seem avoidable. Ironically, PostThreadMessage + MsgWaitForMultipleObjects will probably be the easiest way to set up a reliable communication mechanism between the GUI thread and your "ui" worker thread.
There are several additional places in the Windows API that will enter their own message loop. If you need to continue handling your messages during these times then you'll need a separate thread.

Resources