i have a program which is using several threads to execute some task. Each thread is having a bunch of task to execute. after executing one of them, each thred will call a post message to main screen to update logs.
Now i have sixty thousand tasks ten thousand for each thread – six threads- after executing each task thread is calling post messages. but because of these post messages my application becomes very busy and looks like it hanged.
if i remove post messages…every thing works fine. But i cannot call the procedure directly because it uses ui controls and ui controls are not thread safe and calling procedure directly from thread will lead to other errors.
so is there any alternative available for postmessage and send message.
Thanks,
bASIL
The problem is that there are two message queues for posted messages. The result of this is that your posted messages are always processed before any
Paint,Input, orTimermessages.This means that you are flooding the message queue with a few hundred thousand messages. These messages will always get processed before paint and user messages – making your application appear to hang.
The common way to solve this is to use a timer; have your code start a very short duration (e.g. 0 ms) timer.
When timers fire they send a
WM_TIMERmessage. This message will always be handled after any input and paint messages; making your application appear responsive.The other upside of setting a timer is that it forces you to “queue up” all the items you have processed in a (thread safe) list. You combine a few thousand work items into one “timer”, saving the system from having to generate and process thousands of needless messages.
Bonus Chatter
Update: You should not have a timer polling, that’s just wasteful and wrong. Your threads should “set a flag” (i.e. the timer). This allows your main thread to actually go idle, only waking when there is something to do.
Update Two:
Pseudo-code that demonstrates that order of message generation is not preserved:
Even though i generate a
WM_ProcessNextItemafter i generate aWM_PAINTmessage (i.e.Invalidate), theWM_PAINTwill never get processed, because there is always another posted message before it. And as MSDN says, paint messages will only appear if there are no other posted messages.Update Three: Yes there is only message queue, but here’s why we don’t care:
The Old New Thing, Practical Development Throughout the Evolution of Windows
by Raymond Chen
ISBN 0-321-44030-7
Copyright © 2007 Pearson Education, Inc.
Chapter 15 – How Window Messages Are Delivered and Retrieved, Page 358
It’s easier to imagine there are two message queues. No messages in the “second” one will be read until the “first” queue is empty; and the OP is never letting the first queue drain. As a result none of the “paint” and “input” messages in the second queue are getting processed, making the application appear to hang.
Update Four
The problem isn’t necessarily that you are “flooding” the input queue with your messages. Your application can be unresponsive with only one message. As long as you have one posted message in the queue, it will be processed before any other message.
Imagine a series of events happen:
WM_MOUSEMOVE)WM_LBUTTONDOWN)WM_LBUTTONUP)WM_PAINT)WM_ProcessNextItem)Your application’s main message loop (which calls
GetMessage) will not receive messages in the order in which they happened. It will retrieve theWM_ProcessNextItemmessage. This removes the message from the queue, leaving:WM_MOUSEMOVEWM_LBUTTONDOWNWM_LBUTTONUPWM_PAINTWhile you process your item the user moves the mouse some more, and clicks randomly:
WM_MOUSEMOVEWM_LBUTTONDOWNWM_LBUTTONUPWM_PAINTWM_MOUSEMOVEWM_MOUSEMOVEWM_MOUSEMOVEWM_MOUSEMOVEWM_LBUTTONDOWNWM_LBUTTONUPWM_MOUSEMOVEWM_MOUSEMOVEWM_LBUTTONDOWNWM_LBUTTONUPWM_MOUSEMOVEWM_MOUSEMOVEWM_LBUTTONDOWNWM_LBUTTONUPIn response to your
WM_ProcessNextItemyou post another message back to yourself. You do this because you want to process the outstanding messages first, before continuing to process more items. This will add another posted message to the queue:WM_MOUSEMOVEWM_LBUTTONDOWNWM_LBUTTONUPWM_PAINTWM_MOUSEMOVEWM_MOUSEMOVEWM_MOUSEMOVEWM_MOUSEMOVEWM_LBUTTONDOWNWM_LBUTTONUPWM_MOUSEMOVEWM_MOUSEMOVEWM_LBUTTONDOWNWM_LBUTTONUPWM_MOUSEMOVEWM_MOUSEMOVEWM_LBUTTONDOWNWM_LBUTTONUPWM_ProcessNextItemThe problem starts to become apparent. The next call to
GetMessagewill retrieveWM_ProcessNextItem, leaving the application with a backlog of paint and input messages:WM_MOUSEMOVEWM_LBUTTONDOWNWM_LBUTTONUPWM_PAINTWM_MOUSEMOVEWM_MOUSEMOVEWM_MOUSEMOVEWM_MOUSEMOVEWM_LBUTTONDOWNWM_LBUTTONUPWM_MOUSEMOVEWM_MOUSEMOVEWM_LBUTTONDOWNWM_LBUTTONUPWM_MOUSEMOVEWM_MOUSEMOVEWM_LBUTTONDOWNWM_LBUTTONUPThe solution is to take advantage of the out-of-order processing of messages. Posted messages are always processed before Paint/Input/Timer messages: don’t use a posted message. You can think of the message queue as being divided into two groups: Posted messages and Input messages. Rather than causing the situation where the “Posted” messages queue is never allowed to empty:
You an use a
WM_TIMERmessage:It’s important to note that you’re not polling with a timer, that would be bad™. Instead you’re firing a one-shot timer as a mechanism to generate a
WM_TIMERmessage. You’re doing this because you know that timer messages will not take priority over paint or input messages.Using a timer has another usability advantage. Between
WM_PAINT,WM_TIMER, and input messages, there is out-of-order processing to them as well:WM_PAINT, thenWM_TIMERIf you use a timer to notify your main thread, you can also be guaranteed that you will process paint and user input sooner. This ensures that your application remains responsive. It’s a usability enhancement and you get it for free.