0

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:

  1. 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.
  2. 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?

jhkouy78reu9wx
  • 342
  • 2
  • 8

1 Answers1

2

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.

Soonts
  • 20,079
  • 9
  • 57
  • 130
  • Thank you for answer! I'll consider synchronous messaging you suggested, it looks much better at least for some types of messages. The reason to have a message queue + `WaitFor*`/`GetQueuedCompletionStatus` is possibility to do I/O in the main thread via Alertable I/O or IOCP respectively, also everything doesn't need to be fully reentrant, which is required (if my understanding is correct) if everything is called in-place. – jhkouy78reu9wx Sep 24 '17 at 20:10
  • @jhkouy78reu9wx IOCP is only much better than alertable I/O when you have multiple threads processing completion requests or you have more than MAXIMUM_WAIT_OBJECTS=64 concurrent streams. If you don’t have that many streams, my expectation is WaitForMultipleObjects is just as fast as IOCP. Processing console input in the same queue as async IO could be interesting: user press their keys ~10Hz max, async IO can complete at the rate of 1 KHz or more, however latency-wise you want to prioritize user input. WaitForMultipleObjects is slightly better for that ‘coz it prioritizes handles by order. – Soonts Sep 26 '17 at 20:54