DarkZero
DarkZero

Reputation: 2334

Why semaphore is released but WaitForSingleObject() still stuck?

UPDATE: I found that the semaphore they are releasing is not the semaphore the monitor thread is waiting! I used cout<<ready to find the semaphore the threads are releasing is 00000394, which is not the handle of the semaphore the monitor thread is waiting for. What is the possible reason for this problem? Thank you!


I am new to multithread programming in Windows. Today when I'm writing my online game server, I try to use semaphores in Windows. It is written based on IOCP so that every message is handled in a separate thread. A game consists 4 players.

What I expect it to do is: when receiving a message, a new thread starts and release a ready. There is a monitor thread waiting for 4 ready, and then releases 4 all_ready. Each thread waits one all_ready and goes on.

The code is here:

CGameHost is a manager for a 4-player game.

CGameHost::CGameHost(void)
{
    init_times=0;
    ready = CreateSemaphore(NULL, 0, 4, NULL);
    read = CreateSemaphore(NULL, 0, 4, NULL);
    all_ready = CreateSemaphore(NULL, 0, 4, NULL);
    all_read = CreateSemaphore(NULL, 0, 4, NULL);
    monitor_thread = (HANDLE)_beginthreadex(NULL, 0, Monitor, (LPVOID)this, NULL, 0);
}

unsigned __stdcall CGameHost::Monitor( LPVOID p ) // a static function
{
    CGameHost *nowp = (CGameHost *)p;
    while(true)
    {
        int i;
        for(i=1;i<=MAX_PLAYER;i++)
        {
            WaitForSingleObject(nowp->ready, INFINITE);//stuck here
            cout<<"Get Ready!"<<endl; // This is not outputed, which means it stucks in the last row.
        }

        for(i=1;i<=MAX_PLAYER;i++)
        {
            ReleaseSemaphore(nowp->all_ready, 1, NULL);
        }

        for(i=1; i<=MAX_PLAYER; i++)
        {
            WaitForSingleObject(nowp->read, INFINITE);
        }

        for(i=1; i<=MAX_PLAYER;i++)
        {
            ReleaseSemaphore(nowp->all_read, 1, NULL);
        }
    }
    return 0;
}

void CGameHost::ReleaseReady()
{
    ReleaseSemaphore(ready, 1, NULL);
}

void CGameHost::WaitAllReady()
{
    WaitForSingleObject(all_ready, INFINITE);
}

void CGameHost::ReleaseRead()
{
    ReleaseSemaphore(read, 1, NULL);
}

void CGameHost::WaitAllRead()
{
    WaitForSingleObject(all_read, INFINITE);
}

DataProcess::Game is the message handler for incoming game messages.

CMessage Dataprocess::Game( CMessage* recv_msg )
{
    CMessage ret;
    int now_roomnum = recv_msg->para1;
    int now_playernum = recv_msg->para2;
    if(true)
    {
        cout<<"Received Game Message: "<<endl;
        cout<<"type2 = "<<recv_msg->type2;
        cout<<" player_num = "<<now_playernum<<" msg= "<<recv_msg->msg<<endl;
    }

    if(recv_msg->type2 == MSG_GAME_OPERATION)
    {
        ret.type1 = MSG_GAME;
        ret.type2 = MSG_GAME_OPERATION;

        cout<<"Entered from "<<now_playernum<<endl;

        game_host[now_roomnum].SetMessage(now_playernum, recv_msg->msg);
        game_host[now_roomnum].ReleaseReady();

        cout<<"Released Ready from "<<now_playernum<<endl;//this is shown

        game_host[now_roomnum].WaitAllReady();//stuck here

        cout<<"AllReady from"<<now_playernum<<endl;//not shown

    }
    return ret;
}

Your reply will be of great help for a beginner of Windows multithread programmer like me! Thank you!

Upvotes: 0

Views: 817

Answers (2)

DarkZero
DarkZero

Reputation: 2334

Well, I solved it myself. The reason is that I used CreateSemaphore again after creating the thread, making the player thread visiting different semaphores as the monitor thread... Sorry for my stupidness, and thank you for telling me so much!

Upvotes: 0

Jo&#227;o Augusto
Jo&#227;o Augusto

Reputation: 2305

If I understood your needs, you should probably have something like this..

HANDLE hPlayersReady[4]; HANDLE hAllPlayed;

Create these 5 events, and then on your monitor thread, do something like this...

while(true)
{
// Wait for all players to move
WaitForMultipleObjects(4, &hPlayersReady, true, INFINITE);
// Process move
...
// Advise players the move was processed...
SetEvent(hAllPlayed);
}

And on your player thread X

while(true)
{
// Make my move
...
// Advise monitor I'm ready
SetEvent(hPlayersReady[X]);
// Wait for ready to do another move
WaitForSingleObject(hAllPlayed);
}

Upvotes: 2

Related Questions