views:

319

answers:

3

I'm having trouble keeping my app responsive to user actions. Therefore, I'd like to split message processing between multiple threads.

Can I simply create several threads, reading from the same message queue in all of them, and letting which ever one is able process each message?

If so, how can this be accomplished?

If not, can you suggest another way of resolving this problem?

A: 

Create the separate thread when processing the long operation i.e. keep it simple, the issue is with some code you are running that is taking too long, that's the code that should have a separate thread.

eglasius
+8  A: 

You cannot have more than one thread which interacts with the message pump or any UI elements. That way lies madness.

If there are long processing tasks which can be farmed out to worker threads, you can do it that way, but you'll have to use another thread-safe queue to manage them.

Mark Ransom
But... why? I already have a queue, surely there's some dodgy, half-documented, horrendously-complex means of just re-using it rather than creating *another* one?
Shog9
even if there is some hackish way of doing it, it's not the proper way of handling the problem, like Mark explains.if you're having issues with things like resizing your window, then it sounds like the code that handles WM_SIZE should be looked at.
Idan K
"That way lies madness" is not helpfull; the Windows UI code is simply not thread-safe. No other reason.
Bill
Madness is of course the end result of using code that isn't thread-safe. Pardon my crude attempt to make my writing more interesting.
Mark Ransom
+4  A: 

If this were later in the future, I would say use the Asynchronous Agents APIs (plug for what I'm working on) in the yet to be released Visual Studio 2010 however what I would say given todays tools is to separate the work, specifically in your message passing pump you want to do as little work as possible to identify the message and pass it along to another thread which will process the work (hopefully there isn't Thread Local information that is needed). Passing it along to another thread means inserting it into a thread safe queue of some sort either locked or lock-free and then setting an event that other threads can watch to pull items from the queue (or just pull them directly). You can look at using a 'work stealing queue' with a thread pool for efficiency.

This will accomplish getting the work off the UI thread, to have the UI thread do additional work (like painting the results of that work) you need to generate a windows message to wake up the UI thread and check for the results, an easy way to do this is to have another 'work ready' queue of work objects to execute on the UI thread. imagine an queue that looks like this: threadsafe_queue<function<void(void)> basically you can check if it to see if it is non-empty on the UI thread, and if there are work items then you can execute them inline. You'll want the work objects to be as short lived as possible and preferably not do any blocking at all.

Another technique that can help if you are still seeing jerky movement responsiveness is to either ensure that you're thread callback isn't executing longer that 16ms and that you aren't taking any locks or doing any sort of I/O on the UI thread. There's a series of tools that can help identify these operations, the most freely available is the 'windows performance toolkit'.

I hope this was useful.

-Rick

Rick