Click to See Complete Forum and Search --> : Multithreading and windows procedures


WhorlyWhelk
July 24th, 2007, 03:03 AM
I understand the basic theory behind multithreading (I think) as well as the basic way to do it. So my question is one of design, and I can't find any good resources that discuss this.

I have a GUI with a IRC chat in it as well as the rest of the program.

So I have my main window, and then I create a static window for the chat (with it's own class), the rest of the program in another static window (also has it's own class), and some classes to handle global data in the background.

So how can I multithread this? Do I create new threads when events hit the message queue? Or is there some way to multithread and give each thread it's own message queue? From my understanding the thread is dead when the starting function returns so could I create whole new message queues inside a thread?

Thanks for any responses or resources you can provide that are specifically on multithreading with respect to program design. :-)

MikeAThon
July 24th, 2007, 11:32 AM
I doesn't make sense to force multithreading down the throat of a program, without some idea of what you hope to accomplish, or problem that you hope to solve.

What do you want ot get out of multithreading, in the context of your program?

Mike

kirants
July 24th, 2007, 02:43 PM
Multithreading can be useful sometimes where you have asynchronous events happening, where polling constantly to see if a new event has occured is an overkill.
In your chat case, there could be such events from your communication layer. In your scenario, I can see that there is a GUI element dealing with displaying chat messages and accepting user input. This portion is a good candidate for GUI thread which your applicaiton already has. What could be ( note, could, and not should ) threaded out is the communication portion of it ( sockets , pipes or whatever ). Again, all this, only if needed. For simple applications where the rate of generation of messages is limited by how fast user can "humanly" type, it probably will not make sense.

WhorlyWhelk
July 25th, 2007, 02:31 AM
Sorry I wasn't so clear.

The chat is under a game client. So there are 2 parts...

CLIENT
--------
CHAT

Both have their own classes. They currently draw by passing the hwnd of the parent to the class.

Currently I just run through my event queue doing stuff like client->resize(), chat->login(), etc. It works, but when computations are being done in the client, for example, the GUI and chat are blocked for 5-10 seconds. Also the chat lags the client when messages are being sent/received.

So I'm wondering how I can multithread this. One thought was that I could just create threads when needed and then destroy them. However I'm guessing good multithreading style would be to separate the parts into different threads.

But then I'm not sure what I do. Would I pass messages from the message queue to the different threads when things need to be done? Can these threads have their own message queue?

I think I need a book or something on multithreading since there aren't any good online resources that I can see.

Thanks for any help. :)

MikeAThon
July 25th, 2007, 11:50 AM
Generally, lengthy operations, involving pure number-crunching and no (or limited) interaction with the GUI, are the best candidates for a separate thread.

Also generally, it's best to leave all the GUI operations in one single main thread. Part of the reason for this is that the Windows OS will post messages only to the queue of the thread that created a window. Stated another way, if a worker thread #2 creates a window, then thread #2 must provide a message pump, since Windows will post messages for the window to thread #2's queue and not to the main thread#1's queue.

With this in mind, in your case, it might be best to to move the "computations" to a separate worker thread, so that the GUI elements are not blocked during lenghty operations. The worker thread should have only very limited communications to the GUI thread. Usually, the worker would occassionally post a message (note: not send a message) to one of the main thread's windows. The message is one that is custom defined by you, precisely for this purpose (i.e., #define MYMESSAGE (WM_APP+1)).

Mike

WhorlyWhelk
July 25th, 2007, 03:46 PM
Yea well crunching numbers and using sockets.

So I will try the worker thread. :-)

Where should I create it? Globally? Or right at the start of my program?

JVene
July 25th, 2007, 06:20 PM
To understand how to deploy threading, I propose that you consider there's two concepts at work that require attention.

The thread itself, and the task which is to be performed by that thread. They are unique concepts, but I find that those beginning with the deployment of threads fuse these two into a single concept.

The task is represented by a function, which itself may be a winding road of work, but a single function is its entry point. It may be the nature of this task that you'll call upon it frequently and repeatedly, or you may call upon it occasionally as required by some UI interaction (a button press, for example), or perhaps it represents a task which you'll only perform once in a great while.

Its tempting to think you would launch a thread which calls that function, performing the task, and then the thread simply exits, evaporating. There are occasions when that design approach is appropriate, especially when the overhead of launching the thread is of no concern.

Most often, though, designs require the occasional or frequent repeated calling of that task, and just as often a collection of various tasks which may require threaded service.

In this notion I find many beginners think of opening a thread per task, as the task is called upon for work, allowing the thread to close upon it's completion.

All of this ignores the more technical discussion of parallel programming, I choice I make because your question doesn't seem to branch into that direction, but I mention it for contrast. Parallel implementations divide an algorithm's processing in such a way as increase performance for multiple core machines. The kind of threading you're describing will gain on such machines, but your not discussing a single algorithm's processing in parallel, fortunately.

As such, you should consider which of these tasks can or should operate in parallel, and which can be called upon serially in a thread.

You may have several 'number crunching' tasks which are called upon by UI actions, which can be performed as if in a queue of tasks, one at a time, by one single worker thread. They may not benefit from, themselves, operating in multiple threads (or a thread each).

On the other hand, a thread devoted to communications over sockets ought not be blocked by some existing thread's actions - that is, it shouldn't wait for some number crunching task to complete before it can be serviced. To this end, it seems you have two threads at least, one for each of these two categories of tasks.

I would, if it were my design and I've understood your design correctly, launch two threads each waiting on an auto reset event. These two threads would do nothing at first but wait.

One of these threads is devoted to sockets work, and the other to number crunching tasks. Whenever either task is to be performed, I would have a queue - a container representing member function pointers perhaps, or something similar - which I could trust the thread to service when the event upon which it is waiting is signaled.

It would, thus, be possible to stuff several tasks to be performed, in order, in that queue and let the thread service those tasks in order until the queue is empty. I may stuff one, a dozen or thousands of entries into the queue at once, but instead of launching a thread for each task, that single thread devoted to that category to task would service each one in turn.

The second thread, devoted to sockets work, would be given those tasks.

In my own work I have queue objects that can call any member function of an object, such that it's quite generic. However, as an alternative, it may be that in the case of the sockets thread, you have only a few (perhaps 4 or 6) functions involved. That is, instead of being in the position to call any object's member function, a more generic notion probably lending itself better to the number crunching thread, it may be that you have a 'task' oriented object that represents the socket, which has the few function you intend the sockets thread to operate upon. As such, you can dispense with function pointers are use, perhaps, a switch. For that you might have a queue of objects containing integers, each representing the step to be performed, with what might also be the parameters or buffers upon which that function is to operate.

In either case, the objective is to have an object that represents a thread that generically waits for something to do.

WhorlyWhelk
July 26th, 2007, 04:08 AM
Thank you much JVene. :-)