Thread switching time on 1 core

Started by
5 comments, last by rip-off 7 years, 5 months ago

Hello,

I have a problem with multiplayer being slow on some computers. I

was debugging and discovered there is nothing wrong with the network

part, but with multithreading. 4-core and more processors are

running this good, and 2-core and less have only 2fps net game. So

far I have main program thread, server thread and client handle

thread, when I am considering 2-player game and I am SERVER and main

program, server, and client thread when I am CLIENT (server is there

just because I want him to be prepared to load quickly). Thats 3

threads on 2-core processor, which means that one core will be

running 2 threads, so it would have to switch between them. Printfs

of elapsed miliseonds show me that the time is currently like 500ms.

And I want to change it to 1ms.

Clients have busy-waiting for update packet and servers have busy-

waiting for impulse packet, and I know that solution would be just

to copy the recv part here, but this is not a complete solution

since as the program will expand, there will be a lot more threads -

so far I do not separate Tic and Display threads - this is all

running on main program, but I want. Also, for every next connected

client there is a next handle (so server would have (3+number of

connected players threads). And I just want this to be slick even on

1-core. I tried to change thread priorities, but it does nothing. If

the switching time is unchangeable, then the perfectly OK solution

would be also to say program, that it should jump on other thread

prematurely - is there something like this?

(I use windows.h HANDLE threads)

Advertisement
Don't use busy waiting - use synchronization primitives. It's very hard to actually implement busy wait correctly, so you likely have a bug there.

If a thread doesn't often wait on a synchronization primitive, make sure it includes a Sleep from time to time (such as inside the body of a bad busy wait).

I actually tried to have Sleep in busy wait, but it does not help. I guess the Sleep really sleeps and the OS does no thread switching EVEN when I sleep, so it does not solve problem. Also now I tried function SwitchOnThread, but also it did nothing. Also I have read about processor affinity but that seems to work only for more cores, so I am not interested in. Synchronization primitives, do you mean mutexes? How this even can solve the problém? Lets expect that OS has hardcoded switch of threads after 500ms. Synchronization primitive will wait for something what changes on different thread, so it will anyway change after that 500ms, which I dont want there. I dont much get it.

How are you currently sharing data between threads without the use of synchronization primitives? Maybe also post your busy wait code?

The busy wait function (I already started messing up with mutexes, but they dont work yet):

int WaitPaketS()
{
int navrat_s=0;
int retry_prubeh=0;
clock_t t,t1;
t=3001;
t1=clock();
DWORD dwWaitResult;
for(;;)
{
dwWaitResult = WaitForSingleObject(ghMutex,INFINITE);
if(dwWaitResult==WAIT_OBJECT_0)
{printf("s o %d\n",clock());
//printf("WAIT S\n");
if(t>3000)
{
t1=clock();
if(priznak_byl_vykonan_g)
{
ClientOutputPaketI();
}
retry_prubeh++;
}
t=clock()-t1;
//Sleep(20);
//t1=clock();
bool priznak_nevyskakuj=0;
if(spaket_prijat==0)
{
priznak_nevyskakuj=1;
if (! ReleaseMutex(ghMutex)){/*Handle error.*/}
Sleep(3);
}
if(!priznak_nevyskakuj){break;}
//server se odpojil
if((retry_prubeh>5)|(!client_run)){server_disconnect=1;}
if(server_disconnect)
{
BackToMenu();EndGame();
navrat_s=-1;
CancelConnectionToGame();
break;
}
}
}
if (! ReleaseMutex(ghMutex)){/*Handle error.*/}
//printf("VYSKOK Z WAIT S\n");
return navrat_s;
}

S-packet is update one, i-packet is the impulse one. This one waits for s-packet, i-equivalent is same just with different things. In the net game they check themselves to cross, but on my main PC there was never the problém. I started making change so far just on the client side, and am testing with main PC as server and problém PC as a client (so this piece of code runs on the problém one). I share data through normal global variables.

The OS is WinXP, but problém occured also on Win7 virtual machine. On Win8 4-and-more-core PC it didnt occured, but when I set up virtual machine to have more cores, it doesnt solve the problém, so it could be VMWare bug or maybe the bug is not dependent on number of cores at all. Anyway, the error is periodic - all the time it accepts good s-packet after like 50ms, and another is being interrupted by thread switch, does the busy-wait for like 500ms and gets back to recv. I know that threads are doing big part of this. Cause I have redone the client to be threadless and this function put receiving function into this one and got a net game running on 5fps instead of 2fps with threads. So there must be something wrong with mutexes. I think it doesnt switch.

Anyway, the problém is split between multithreading and networking and the bigger part of problém is networking - in singleplayer I get like 25fps to 60fps (Im in middle of optimization) on the buggy PC but only 5fps in net game without threads. So there must be something wrong with receiving or sending. The receive sometimes také very long time and I am looking on that function and see that I do recv char-by-char (len=1). Do you have any idea?

I debugged a lot more, and the problém is in recv function, so I better moved this one to mulitplayer & networking:

http://www.gamedev.net/topic/683801-recv-timeout-is-5155ms-bigger-then-i-set/

Mutexes should be held for as short a time as possible, you generally do not want to be calling complex or third party code while holding one. That function calls several other functions that appear quite complicated.

While it is difficult to understand that code due to the lack of indentation (note: use the editor to create a code block or write [ code ] ... [ /code ]), I think that there is a lot of flow control in that function and it isn't obvious to me that the mutex handling is correct. If you're using C++, consider using the standard library mutex objects, as they help avoid mismatches and also handle cases like exceptions.

This topic is closed to new replies.

Advertisement