Holy cow, I wrote a book!
Once upon a time, a long, long time ago,
there was a research team inside Microsoft who was working
on alternate models for handling input.
I don't know what eventually came of that project,
and I don't even remember the details of the meeting,
but I do remember the punch line,
so I'm just going to make up the rest.
The research project broke up the duties of their system
into a few components.
The two that are important to the story are a
driver component which received information from various
hardware devices and transmitted that information via the
PostMessage function to another component
whose job it was to study those input messages and route
them to the appropriate application.
(In 16-bit Windows, the PostMessage function
was specifically written so it could be called from device
drivers during hardware interrupts.)
Each time the driver received information from a hardware
device, it posted a message to its helper program.
Everything seemed to go reasonably smoothly.
The device driver received a hardware event,
it posted a message to the helper program,
and the helper program retrieved the message
and processed it.
But once they cranked up the hardware devices to
produce information at a higher rate (and therefore
produced input with much finer resolution),
the events started coming in faster and faster,
and their design started to collapse under the pressure.
The research team asked to meet with the user interface team
to help work out their problems under load.
They outlined their design and explained that it worked
well at low data rates,
"but then we ran onto problems when we started posting
10,000 messages per second."
At that point, the heads of all the user interface people
just sat there and boggled for a few seconds.
"That's like saying your Toyota Camry has stability problems
once you get over 500 miles per hour."
If you're going to be pumping huge quantities of data through
the message queue,
creating a separate message for each one is crazy.
Think about it: Suppose you're posting 10,000 messages per second.
The thread whose job it is to process the messages gets pre-empted
and doesn't run for 50 milliseconds.
That's 500 messages behind schedule already.
Now suppose it takes a dozen page faults (which take 8ms each, say).
Now you're another 1000 messages behind.
Windows NT sets
an arbitrary limit of 10,000 unprocessed messages
in a message queue
so that a runaway program won't drain
the desktop heap and roach everything.
A few hiccups in your process will quickly send you over that limit.
For this usage pattern, you want to switch from
one event per message
to a signal on the transition
(or edge triggering).
When the first event occurs,
post a single message to the helper program saying
there is work to do and set a flag saying
helper window has been notified.
Meanwhile, stash the information you would have included in the message
into a privately-managed queue.
If an event arrives when the
helper window has been notified
flag is set, then don't post a message;
just append the work item to the queue.
When the helper window receives the there is work to do
message, it calls back into the driver to say
Okay, give me some work to do.
After it does the work, it calls into the driver to say
Okay, what else do you want me to do?
(Alternatively, you can have the helper window grab the entire work list
When the helper window asks for work to do and comes back empty-handed,
then clear the
helper window has been notified
flag so the next time an event occurs,
a new message will be posted to kick-start the helper window.
Commenter Hayden proposed a number of other mechanisms.
send a list of work items rather than just one
technique works well if you know when the list of work items is complete
and therefore is ready to send.
The second technique is the one I described here;
it works well if the producer doesn't really know when each chunk of incoming
work is finished, or if the work that comes in is continuous.
The third mechanism merely avoids the message queue altogether and
uses a semaphore instead.
The point is not to try to drive your Camry at 500 miles per hour.
Find a way to get your work done while keeping the Camry well within
its design parameters,
or look for a different vehicle.