简体   繁体   中英

How to block a thread while other threads are waiting

I have a very specific problem to solve. I'm pretty sure someone else in the world has already encountered and solved it but I didn't find any solutions yet.

Here it is :

  • I have a thread that pop command from a queue and execute them asynchronously
  • I can call from any other thread a function to execute a command synchronously, bypassing the queue mechanism, returning a result, and taking priority of execution (after the current execution is over).
  • I have a mutex protecting a command execution so only one is executed at a time The problem is, with a simple mutex, I have no certitude that a synchronous call will get the mutex before the asynchronous thread when in conflict. In fact, our test shows that the allocation is very unfair and that the asynchronous thread always win.

So I want to block the asynchronous thread while there is a synchronous call waiting. I don't know in advance how many synchronous call can be made, and I don't control the threads that make the calls (so any solution using a pool of threads is not possible).

I'm using C++ and Microsoft library. I know the basic synchronization objects, but maybe there is an more advance object or method suitable for my problem that I don't know.

I'm open to any idea!

Ok so I finally get the chance to close this. I tried some of the solution proposed here and in the link posted. In the end, I combined a mutex for the command execution and a counter of awaiting sync calls (the counter is also protected by a mutex of course). The async thread check the counter before trying to get the mutex, and wait the counter to be 0. Also, to avoid a loop with sleep, I added an event that is set when the counter is set to 0. The async thread wait for this event before trying to get the mutex.

void incrementSyncCounter()
{
    DLGuardThread guard(_counterMutex);
    _synchCount++;
}

void decrementSyncCounter()
{
    DLGuardThread guard(_counterMutex);
    _synchCount--;

    // If the counter is 0, it means that no other sync call is waiting, so we notify the main thread by setting the event
    if(_synchCount == 0)
    {
        _counterEvent.set();
    }
}

unsigned long getSyncCounter()
{
    DLGuardThread guard(_counterMutex);
    return _synchCount;
}

bool executeCommand(Command* command)
{
    // Increment the sync call counter so the main thread can be locked while at least one sync call is waiting
    incrementSyncCounter();

    // Execute the command using mutex protection
    DLGuardThread guard(_theCommandMutex);
    bool res = command->execute();
    guard.release();

    // Decrement the sync call counter so the main thread can be unlocked if there is no sync call waiting
    decrementSyncCounter();

    return res;
}

void main ()
{
    [...]
    // Infinite loop
    while(!_bStop)
    {
        // While the Synchronous call counter is not 0, this main thread is locked to give priority to the sync calls.
        // _counterEvent will be set when the counter is decremented to 0, then this thread will check the value once again to be sure no other call has arrived inbetween.
        while(getSyncCounter() > 0)
        {
            ::WaitForSingleObject (_counterEvent.hEvent(), INFINITE);
        }

        // Take mutex
        DLGuardThread guard(_theCommandMutex);

        status = command->execute();

        // Release mutex
        guard.release();
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM