Multi-threading Question

Started by
24 comments, last by Dragonskin 22 years, 3 months ago
Here's the "relevant" parts.

      unsigned WINAPI GameThread(LPVOID arg1) {	// Run the window's game loop	OpenGLWindow.RunGame();	// The thread is done, alert the message handler	PostMessage(NULL,WM_CLOSE,0,0);	// Alert the main thread that this thread is done	GameThreadDoneCS.On();	// Ensuring we're the only ones writing right now	GameThreadDone = true;	GameThreadDoneCS.Off();	// Protection is over	return 0;}// Main windows functionint WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {	MSG msg;			// For processing messages	bool done;			// For the main loop	// Get the screen resolution to run in	if (!OpenGLWindow.ChooseScreenRes(hInstance))		return 0;			// Didn't click the OK button	// Loop around unless we aren't toggling fullscreen mode	do {		GameThreadDoneCS.On();	// I think I'm getting carried away with these, but I'm not taking many chances		GameThreadDone = false;		GameThreadDoneCS.Off();	// Protection off		// Create the OpenGL window (but not everything)		if (!OpenGLWindow.CreateWnd(ProgramName, CustomGLWndProc)) {			MessageBox(NULL,"Unable to create new window (in main)","ERROR",MB_OK|MB_ICONEXCLAMATION);			return 0;			// Problem creating the window		}		done = false;		// Main message pump loop		while (!done) {			// Get any message that may be waiting			if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {				// Is it a quit message?				if (msg.message == WM_QUIT) {					// Program is over					done = true;				} else {					// Process the message					TranslateMessage(&msg);					DispatchMessage(&msg);				}			}			// Check to see if the thread is done yet so we can exit			if ((GameThreadDone == true) && (ToggleFullscreen == true)) {				done = true;			} else if (GameThreadDone == true) {				PostQuitMessage(0);			}			if (!bProgramActive)				WaitMessage();		// Releases control until another message comes		}		OpenGLWindow.DestroyWnd();	} while (ToggleFullscreen == true);	return int(msg.wParam);	// Exit code}    


This is the way that works. I really don't want to terminate the thread by any means other than returning, so I'm keeping away from TerminateThread (especially since THIS works).

All I'm doing to test the GetMessage is converting PeekMessage to GetMessage (and removing PM_REMOVE, of course) and then taking out the WaitMessage stuff.

I've tried moving around the order I tell the main loop my thread is done (post the message afterwards) but it will still hang at the GetMessage. At least, I'm assuming that's where it's hanging because that's the statement the debugger is always on when I pause execution.

Edited by - Dragonskin on December 20, 2001 4:51:40 PM
Advertisement
So, why are you passing NULL as the hWnd to PostMessage() in your thread? You should probably be using PostThreadMessage() here. This will probably solve your GetMessage() problem.

Probably better to use for this though are Events. Create an event that is used to signal the thread is shutting down (instead of having GameThreadDone). Events are atomic, so you don''t need to protect them with critical sections, etc. Then you can use WaitForSingleObject(hEvent, 0) to poll the event to see if it''s set yet (WaitForSingleObject doesn''t need to be protected either).


-Brannon
-Brannon
Now that I look at it again I don''t even NEED that PostMessage in there, because the window is already closing and the thread is exiting. I think it was leftover from when the window was created in the second thread. I removed it and it still works (with PeekMessage).

As for changing it to PostThreadMessage, I''ve looked at the MSDN docs and it doesn''t mention what the ThreadID of the initial thread is. I store the second thread''s ID, but you never get the first one because it''s your main loop.

And I''m going to look into the events. Thanks!
You're going about it in a convoluted way...

  //Global handlesHANDLE g_thrGameLoop=INVALID_HANDLE_VALUE;HANDLE g_evExit==INVALID_HANDLE_VALUE;HANDLE h_hMainWnd;  



WinMain/Main Thread
        //...g_evExit = CreateEvent(NULL, TRUE, FALSE, 0);//The thread is created in one of the init window messages// as is g_hMainWnd;while (GetMessage(&msg, NULL, 0, 0)) 	{	if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 		{		TranslateMessage(&msg);		DispatchMessage(&msg);		}	}SetEvent(g_evExit);if(WAIT_OBJECT_0!=WaitForSingleObject(g_thrGameLoop, 5000))	{	OutputDebugString("GameLoop Thread Failed to exit gracefully!!!!\n");	TerminateThread(m_thrGamLoop, -42);	}CloseHandle(m_evExit);CloseHandle(m_thrGameLoop);return(0);  


//GameLoop
  DWORD dwYieldTime_ms = 0;while(WAIT_OBJECT_0!=WaitForSingleObject(g_evExit, dwYieldTime_ms))	{	//Game Loop goes here	if(DecideToQuit())		{		PostMessage(h_hMainWnd, WM_QUIT, 0, 0);		}	}		//Clean-up	return(0);	  


Magmai Kai Holmlor

"Oh, like you've never written buggy code" - Lee

"What I see is a system that _could do anything - but currently does nothing !" - Anonymous CEO


Edited by - Magmai Kai Holmlor on December 20, 2001 8:37:27 PM
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
I understand the convoluted part. The reason that I checked for WM_QUIT messages to exit the loop was because, well, I was using PeekMessage and it doesn't return 0 when a quit message comes through. Guess I should have looked to make sure exactly GetMessage's return value was, huh? After reading your code I decided to check again... makes me want to say "argh" all night, if you know what I mean.

Thank you, again. I have GetMessage working, and now I don't have to explicitly wait when the program isn't active. That actually had a bug that I didn't think of until a bit ago...if it was minimized and you right-click and close it, it'd run into the same problem the GetMessage was earlier. That could be gotten around by checking to see if the thread was active or not, but this is MUCH better.

Major thanks!!!!!

Edited by - Dragonskin on December 20, 2001 9:42:47 PM
quote:Original post by Magmai Kai Holmlor
You''re going about it in a convoluted way...

I prefer the term "Rube Goldberg."

This topic is closed to new replies.

Advertisement