Windows Messages, Multi-threading, OpenGL and me

Started by
6 comments, last by that1guy 22 years, 9 months ago
I am writing a simple "test bed" app to test new things I learn.. I''m currently working on network communications.. (a little off opengl topic I know but don''t slap me just yet).. Anyway, up to this point I''ve simply been using Tutorial 1''s project. In researching how to best handle server-client communications in a game and it is pointed that you don''t want to wait around for all your rendering code to complete before checking for the next message from windows (notifying you that there''s a packet to receive), basically this would mean an instant +40ms lag time right out the gate.. makes sense.. So, I''ve tried to create a simple thread that does nothing but watch for messages.. when a message comes through, it sets a flag and keeps going.. The thread handling code goes something like this: DWORD WINAPI WindowsMessagingThread(LPVOID) { MSG msg; while (GetMessage(&msg, hWnd,0,0)) // wait for a message { TranslateMessage(&msg); // Translate the message DispatchMessage(&msg); // Dispatch the message } return 0; } and the code to start the thread: MessageThread = CreateThread(NULL, 0, WindowsMessagingThread, 0, NULL, &MessageThreadID); Debugging into the code says the main process does in fact run as expected, the scene simply re-draws itself over and over and over. But the above thread that gets the messages above seems to grab a message or two and then just stops accepting any messages from windows. In fact it crashes the program taking Windows with it.. I think this might be a bad thing.. anyway.. any thoughts? Now, assume that I have indead created the window (some people have actually suggested that this is why it doesn''t work) registered WndProc() properly and that hWnd is valid and visible to both the main process and the thread. If I take out the thread call and simply check for windows messages (using PeekMessage) in the main loop, everything works fine (btw, PeekMessage doesn''t help in the secondary thread either =). Also, if I move the windows creation code into the secondary thread, the window is created and actually accepts messages BUT OpenGL doesn''t want to draw to it. The only theory I have now (and I''m grasping at straws here) is that even though hWnd maybe global within the main.cpp file (which both WinMain() and WindowsMessagingThread() reside in), the secondary thread does not have access to it, or worse yet, a seperate copy? I have read that a second thread like this should share data between it and the main process (and to be very carefull to keep data threadsafe). So I''m at a loss.. if anyone has any ideas, please please please share them with me =) Thanks! -Jon "Ah hell.. it doesn''''t work.. AGAIN!"
"Ah hell.. it doesn''t work.. AGAIN!"
Advertisement
urgh, this happens to me too, only my program doesnt crash - my tcp message handler just stops retrieving packets.. Can''t help you though, im dumbfolded.. any help people?

"You are just as irritating to me as an irrational term that accidentially creeps into your equation and cannot be factorized out."
GetMessage and PeekMessage work only for one thread, so a window created in thread A will have all it''s messages posted to thread A. Calling GetMessage in any other thread won''t do anything.

Also, if you create a window in one thread but create opengl in another, you''ll have problems as well, since any messages opengl tries to send to the thread will be asyncronous (you can''t post syncronous messages to another - I think...)

Anyway, there''s two solutions. One, simply create the opengl rendering context in the second thread as well (this is OK since opengl is thread safe, as long as you create the rendering context in the same thread as the window).

The other (perhaps better) was is to create a dummy window in the second thread, and use that window to receive your network messages. Just create a window with the WS_POPUP flag and a width/height of 0. I''d say this method is better since your rendering code and your networking code are completely unrelated then. You can destroy your rendering window and create a new one (for example when going between fullscreen and windowed) without worrying about the networking code.

War Worlds - A 3D Real-Time Strategy game in development.
Hey all!

I took Dean''s advice and simply created a window for the client and server DLL''s, and things work fine.. The only setback I had was that the DLL''s run in the same process as the main rendering code, but different threads, and spawning them with the default normal thread priority stole too much time from the rendering.. lowered the priority and things work fine (but am I now taking too much time from the dll''s?) I dunno, but I''ll make sure to keep this thread updated with what I find.. gut feeling is that the client/server threads have plenty of time to do their job.

Thanks!
-t1g

"Ah hell.. it doesn''''t work.. AGAIN!"
"Ah hell.. it doesn''t work.. AGAIN!"
Generally... your main thread is going to be your system thread.. which also means keeping your message pump there (which still operates much faster as a threaded setup can get you around the complexities of finite state setups working with the message pump).

Initialize your system here, including OpenGL, DirectX, whatever global things you have... then create a thread.. move basically you game control into this thread... it should work

Sorry this is veru vague.. I am in a hurry ^^

Bets of luck,
Clifford M. Roche
Gamedev's AI Auto-Reply bot.
If I may make another suggestion...

Since you''ve got your networking code in another thread, is there really any need to use asyncronous sockets? If you just use normal blocking sockets, you don''t need to create a second window to recieve messages, and the networking thread won''t take any CPU at all, until a packet arrives on the socket.

If you''re writing a client which only has one network socket (to the server) this is easy, the thread just goes like this:

[/source]
while( true )
{
recv(...); // this will block

// now process whatever was recieved
// and wait for more
}
[/source]

In you main thread, you can use send() whenever you want to send updates to the server (sockets is multithreaded, so you should be able to send and recieve at the same time)

If you''re doing the server, or your networking is peer-to-peer, then it''s slightly more complicated, since you can recieve from many different sockets at any given time. To do this though, you just need to look into overlapped I/O and I/O completion ports. Basically, you create a bunch of "ports" for each socket, and you block on the ports. When something arrives on a socket, the OS wakes the thread up and you can process it. You can also use this method to do asyncronous writes on multiple sockets.

It''s a bit more difficult to set up, but I think once you get it working, it''s more flexible and far more efficient, since your networking thread is blocked on a function (hence taking 0 CPU time) until it receives data.

If you have the Platform SDK, there''s a good sample on using I/O ports with sockets in the POP3 winsock sample. I''m not at home to give you much more details, but I think this method is better than the message-loop version.

War Worlds - A 3D Real-Time Strategy game in development.
I''m back =)

I spawned a server thread and client thread off the main process and they are lagging the main process pretty badly, they''re stealling too much cpu time even though both have VERY simple inner loops (for now).

I have actually tried to create a seperate thread to run rendering in, taking care of messages through the main process but OpenGL didn''t want to draw to a window created outside it''s thread (any hints on how you did it?)

Dean:
That would be the ideal solution, one which I haven''t yet thrown out. The problem is that the server, when not processing messages, will be updating all clients about the state of the game (this is just a chess game so I could get away with not doing this, but the whole reason to do any of this for me is to learn how to do FPS games, so I want to do it the "right" way, if there is such a thing). Same for the client

Here''s an idea that I really don''t know if it''ll work but it''s a thought. In both the client and server main loops I''m using PeekMessage() rather then GetMessage(), (so that it could do other things while waiting). I could post a message from the main process every milliseconds that would tell the server to send out updates, and milliseconds that would tell the client to send a "I''m still here" message. This way I could use GetMessage() and save some cycles.

As usual, thanks for your help =)
-t1g

"Ah hell.. it doesn''''t work.. AGAIN!"
"Ah hell.. it doesn''t work.. AGAIN!"
I think that overlapped I/O is definatly what you''re looking for. You can do overlapped writes so that you can update your clients whenever you want (even from other threads). Plus, your network thread is *always* blocked and taking 0 CPU, unless there''s data to read, or a write operation has finished.

If you look at the POP3 sample, it shows you pretty much everything you need to know, it does overlapped reads, as well as writes (it even transfers files, but I don''t think you''ll need that )

War Worlds - A 3D Real-Time Strategy game in development.

This topic is closed to new replies.

Advertisement