Sign in to follow this  
BeanDog

Something better than Sleep(0)?

Recommended Posts

BeanDog    1065
I'm writing a multiplayer game, but although my question is in the context of such, it is more appropriate to this forum. In order to make my code more coherent, I decided that everyone, including the player whose computer is being used as server, needs to open some sockets to the server application to play the game. The server application is a Win32 console application that starts up when the game begins (for debugging purposes). So I have two applications running simultaneously that both need fairly consistent chunks of the processor time. At first, my server was hogging 98% of the CPU, since it does basically nothing but number-crunching. So, in the main loop of the server, I put the old coding classic:
Sleep(10);
I later tried reducing the value to 1 or 0, but it doesn't change the fact that Sleep() takes a seemingly random time between 0 and 500 milliseconds to return, which obviously seriously screws up my server. I have to have both of these processes running through their main loop at least several dozen times per second, without hogging 100% of the CPU when they don't need all that time. I'm at a loss. What do I do? ~BenDilts( void );

Share this post


Link to post
Share on other sites
kburkhart84    3187
I never use Sleep for that purpose. As far as I know, if you are running your Message Pump, windows will automatically share the processor with other programs and with yours without you putting any Sleeps in the loop. I wouldn't go by the 98% that is stated in the Task manager because in a constant loop, you get 100% CPU usage, but 2% in this case probably went to the Task Manager itself processing your clicks to see the number in the first place.

Share this post


Link to post
Share on other sites
BeanDog    1065
I made the server a console application in this instance for easy output of diagnostics that were easy to read. Console applications don't exactly have the same metaphor of a message pump, unless I'm seriously mistaken. Should I recreate my console app as a regular Win32 project, or is there some hack I could do in the meantime?

Update: I created an invisible window in the server application and now run a message pump on it during the server's main loop. But this code:

if( PeekMessage( &msg, NULL, 0U, 0U, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}

sometimes takes over 1/4 of a second to complete. I figure it's because the window is running in the background (not focused). It appears that this is sort of the case with a console window, as well (longer time between timeslices).



~BenDilts( void );

[Edited by - BeanDog on October 6, 2005 11:14:23 PM]

Share this post


Link to post
Share on other sites
iMalc    2466
Quote:
Original post by BeanDog
I later tried reducing the value to 1 or 0, but it doesn't change the fact that Sleep() takes a seemingly random time between 0 and 500 milliseconds to return, which obviously seriously screws up my server.

I have to have both of these processes running through their main loop at least several dozen times per second, without hogging 100% of the CPU when they don't need all that time.
So do both processes have a sleep(0) in them? If not then obviously your other process is stealing away time from this one at every opportunity. Sleep wouldn't take very long if there wasn't much else that really needed to be done.

If a single delay being 500ms long screws up your server then you may have a design problem. You shouldn't be relying on getting perfectly regular amounts of CPU time. If it does, you simply compensate. It can quite easily happen once in a while if you get a few page faults, because you have other apps open too.

So when it 'screws up', what exactly happens?

Share this post


Link to post
Share on other sites
BeanDog    1065
Nothing too drastic happens--The players just jump positions drastically. It wouldn't be a problem if it happened a couple times an hour, but it happens about every 2-3 seconds.



~BenDilts( void );

Share this post


Link to post
Share on other sites
BeanDog    1065
Problem isolated: This is not an issue when I don't run my program in the integrated debugger. I guess the IDE is sucking down too much CPU. Sorry for the trouble, guys. It's going to be a pain to debug this w/o the integrated debugger...



~BenDilts( void );

Share this post


Link to post
Share on other sites
Andrew Russell    1394
Might I suggest an appropriate fix would be a fixed timestep. Then you could just run as many steps to "catch up" to the current time as necessary, and only run your Sleep() function when you have caught up (so you don't sleep when your program is lagging).

Because your time steps are fixed, they cannot grow extreemly long when your application is waiting for Sleep to return (or for something to page, or some other process).

Although you'll need a "bailout" method if you end up many milliseconds "late". You may also need some interpolation (particularly in the client).


Article worth reading, about network timing (about physics, but the theory applies to anything at all).

Share this post


Link to post
Share on other sites
Quote:
Original post by BeanDog
This is not an issue when I don't run my program in the integrated debugger. I guess the IDE is sucking down too much CPU. Sorry for the trouble, guys. It's going to be a pain to debug this w/o the integrated debugger...


Quick question: Are you handling a lot of exceptions at any point? I recently made a .net application in MSVC2005 Express Beta and when I had a lot of handled exceptions the program would slow to a crawl when attached to a debugger, but run fine otherwise. By preempting the error condition (putting in "if(wouldHaveError) { handleError(); } else { try { do(); } catch(System::Exception^) { handleError();} }"), it would run fine in the debugger too.

Now I don't know if it was because of 2005, .net, or simply exceptions running through a debugger, so I just thought I'd throw that out there as something to consider.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster   
Guest Anonymous Poster
Your problem is that you need to give relief to the system. Sleep() does not do this, you need something like

::WaitForSingleObject( , ) ;

This will give relief to the system and let other threads and processes run.

Share this post


Link to post
Share on other sites
iMalc    2466
Quote:
Original post by Anonymous Poster
Your problem is that you need to give relief to the system. Sleep() does not do this, you need something like

::WaitForSingleObject( , ) ;

This will give relief to the system and let other threads and processes run.
Other threads and processes most certainly can run when your program calls Sleep()!
Perhaps you're thinking of MsgWaitForSingleObject which allows even the current thread to process messages as well, though that can cause reentrancy issues.

Share this post


Link to post
Share on other sites
andhow    130
On the subject of Sleep() sleeping for erratic amounts of time:
Its important to understand how Windows does scheduling. Sleep() puts your thread in a list of threads waiting to run. This is the same list you go to when you block on file i/o. This is a good place to be because you don't waste any CPU cycles in the waiting list because you are never scheduled to execute. (So the previous post about Sleep not giving the system a break is completely incorrect).

When the timeout of the Sleep() finishes (after however many milliseconds), Windows doesn't immediately yank your thread out of the Waiting queue and run the thread. Instead, it waits for the timeslice of the current thread to finish and then when it considers which thread to schedule next, it sees your thread has finished Sleeping and runs it. So the critical question is how long is this timeslice? On Windows Client, I've found its around 15 ms, and on Windows Server, it can be much longer. So lets say you Sleep() right after Windows did its rescheduling, you'll have to wait another 15 ms until you are even eligble to run. If you Sleep(1) 2 milliseconds before Windows reschedules, then you will get a much faster turnaround.

Share this post


Link to post
Share on other sites
Shannon Barber    1681
Windows is not an RTOS and the only guarantee made by Sleep is that your thread will be rescheduled. Even with Sleep(0) you will get 200ms+ sleep times if the machine is under heavy load.

Your problem is architectural. It is a mistake to have 2 threads/process compete for the same resource. An RTOS wouldn't fix the problem either because there is not enough CPU available to you.

Share this post


Link to post
Share on other sites
andhow    130
You said you Sleep() in the server's main loop, do you also Sleep() in your client's main loop? If you don't, then what will happen is the server will run a quick frame, Sleep(), and then your Client will hog all resources until it gets preempted. If both are doing Sleep(0) (assuming they are the same priority), then they should roughly take turns running one frame apiece.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this