(c++ win32) handling the game thread when the window is minimized

Started by
8 comments, last by Colin Jeanne 17 years ago
In my game I've created a seperate thread to run the game loop while the default one just handles the window and msgproc. It seems to run fine, but when I minimize the window, the computer goes really slow, and I have a hard time closing the window, although it seems to be ok if I don't minimize it but click on a different windows allowing the game to run in the background This is what I'm doing.

//create window...

HANDLE thread = CreateThread(0,0,(LPTHREAD_START_ROUTINE)gameThread,0,0,0);
SetThreadPriority(thread, THREAD_PRIORITY_ABOVE_NORMAL);

MSG msg = {0};

while(GetMessage(&msg, 0,0,0)) {
	TranslateMessage(&msg); 
	DispatchMessage(&msg); 
}

CloseHandle(thread);



And the gameThread is basically this:

//init d3d, dinput, dsound, game data...

while(IsWindowVisible(window)) { 
  //run....
}

//uninit....


Why does it start freezing when I minimize the window? and should I be doing anything else to make sure the thread ends, say if the program's process was ended using windows task manager? Also as the 'HWND window' is also read by the game thread, and is the basis of the default window thread, must I worry about preventing the two threads from acessing it at the same time? Thanks
Advertisement
IsWindowVisible() tests to see if a window is visible, not if it's not minimized. Minimized windows are still visible. Use IsIconic() to see if a window is minimized. What you probably want to do, however, is handle WM_ACTIVATE and suspend your game loop thread when your window is no longer active and then resume it when your window becomes active again. You can do this either with SuspendThread()/ResumeThread() or use some isWindowActive variable in your while loop.

As for HWND window - as long as the threads arent writing to that variable (which they probably arent) you should be ok. The real problem occurs when either two threads try to write a variable at the same time or one is writing while the other is reading. If both are reading, that's fine.
Quote:Original post by johnnyBravo
Why does it start freezing when I minimize the window?


Because one of your threads (the game thread I'd imagine) suddenly gets the highest priority and starts using up 100% of your cpu.

Use the technique Colin Jeanne outlined to ensure that it's only updated when the window is visible. Or, have the thread sleep a millisecond each frame.
Quote:Original post by gharen2
Or, have the thread sleep a millisecond each frame.


I'd, actually, recommend sleeping a little longer. You don't really need to update that often, when the game is minimized - 10 updates per second would be more than enough, IMO.
Quote:SetThreadPriority(thread, THREAD_PRIORITY_ABOVE_NORMAL);
This is a bit of a problem too, especially if you intend your game to run nicely when the user is multitasking (For that matter, who seriously multi tasks while playing a game?). I would call any program that's not content with running at normal priority obnoxious.
Windows will dynamically fiddle with your priorities when you do things in the system. For example by default on non-server versions the foreground app gets a small priority boost to make it more responsive to the user. I haven't checked but it seems quite likely the minimizing your window will cause the system to drop your priority (cause if it's minimized you aint using it). Then, becuase you have a higher priority thread that's probably largely cpu-bound, and because maybe there are other threads in the system that are now suddenly higher than you are, your first thread doesn't get many cycles.

Is your game thread doing UI stuff or is it just logic? If it's doing UI stuff there's not really any point in running it on a different thread then the message loop.

IMHO it's mildly evil for apps to increase thier own priority. It makes it harder for the user to get things running the way they want as opposed to the way apps think they should run.
-Mike
Quote:Original post by Paulius Maruska
Quote:Original post by gharen2
Or, have the thread sleep a millisecond each frame.


I'd, actually, recommend sleeping a little longer. You don't really need to update that often, when the game is minimized - 10 updates per second would be more than enough, IMO.


I set it to 1ms, but I don't really see how making it larger make a difference, it reminds me of 'DoEvents' from vb6, back when I used sleep as my timer :)

Quote:Original post by Colin Jeanne
As for HWND window - as long as the threads arent writing to that variable (which they probably arent) you should be ok. The real problem occurs when either two threads try to write a variable at the same time or one is writing while the other is reading. If both are reading, that's fine.


I see, how about when the window is being resized, would that modify the hwnd? Because I am always checking the size of the window for the projection matrix and buffer width/height to use in resetting the d3d device.


Quote:Original post by Anon Mike
Is your game thread doing UI stuff or is it just logic? If it's doing UI stuff there's not really any point in running it on a different thread then the message loop.


Just logic, though I did it only because when you drag, resize or right click the title bar on the window the game would stop because of the message loop,

and when the game loop started running again the game objects would jump forward a couple of seconds, I managed to zero the timer on everything but right clicking on the title bar, I couldn't work out how to detect that.

I am a bit apprehensive about using threads for something like that, but it really bugged me.


Also something else, d3d device seems to get lost if you minimize for more than a couple of seconds, it never did that when I used only the default thread, it is being handled but I'm wondering why it is lost so easily now?



Thanks alot guys.




Quote:Original post by johnnyBravo
Quote:Original post by Colin Jeanne
As for HWND window - as long as the threads arent writing to that variable (which they probably arent) you should be ok. The real problem occurs when either two threads try to write a variable at the same time or one is writing while the other is reading. If both are reading, that's fine.


I see, how about when the window is being resized, would that modify the hwnd? Because I am always checking the size of the window for the projection matrix and buffer width/height to use in resetting the d3d device.


That might be a problem. You probably want to pause your game when the user is resizing your game's window (does it need to be sizable)? When your window receives WM_ENTERSIZEMOVE suspend your thread and when your window receives WM_EXITSIZEMOVE resume your thread.
If there were to be a conflict, eg one thread trying to read while another is writing, how would I know it happened, would it crash?

As I did a test of reading an integer, while the other thread incremented it, but it still ran fine.
thx
Your program probably wouldnt crash. What would happen is that there is a possibility that a read is not a trivial operation - it might be multi-instruction. What could happen then is that one thread would be half way through a read operation when it is suddenly switched out and the thread which writes to the value is switched in. That thread does its write and then the read thread is switched back in and completes the operation. It would then have read half of the old value and half of the new value. Whoops!

I could definitely see this happening when updating the size of the window when you are reading that size to set your projection matrix, as an example.

If it happened that the value that was being read from and written to was a pointer then reading half of its old value and half of its new value and then dereferencing it would probably lead to a crash. If you're lucky.

Testing for this kind of problem is also very difficult. You dont have control over context switching so you cant force one thread to write to a value while the other is reading.

This topic is closed to new replies.

Advertisement