3
votes

I'm writing a thread safe queue using C++11 and stl threading. The WaitAndPop method currently looks like the following. I would like to be able to pass something to WaitAndPop that indicates if the calling thread has been asked to stop. WaitAndPop should return true if it waited for and returned an element of the queue, it should return false if the calling thread is being stopped.

    bool WaitAndPop(T& value, std::condition_variable callingThreadStopRequested)
    {
        std::unique_lock<std::mutex> lock(mutex);
        while( queuedTasks.empty() )
        {
            queuedTasksCondition.wait(lock);
        }

        value = queue.front();
        queue.pop_front();
        return true;
    }

Is it possible to code something like this? I'm used to a Win32 WaitForMultipleObjects, but can't find an alternative that works for this case.

Thanks.

I've seen this related question, but it didn't really answer the problem. learning threads on linux

1
My solution to a POSIX WaitForMultipleEvents was using poll() and using pipes for the events. I don't think that's going to help you with your condition variables, however...trojanfoe
I would say this is a recommended way as described by Antony Williams in "Implementing a Thread-Safe Queue using Condition Variables"- justsoftwaresolutions.co.uk/threading/….SChepurin
Hmm, yes, I see that. It is a thread safe queue, but also doesn't offer the ability to abandon a wait if a thread needs to be stopped (well, not without spinning which any good threader would want to avoid).Scott Langham
Possibly I can push some special value onto the queue in a shutdown scenario which tells WaitAndPop to return false when it pops that value. And I might be able to make it jump to the front of the queue too for quicker termination.Scott Langham
I think you have to mutualize the cond variable on all the things you wish the thread to wait for. It's the easiest way. Otherwise, you could revert to using fs objects and use select/poll, but this is posix, not pure C++, so... There's really no equivalent of WaitForMultipleObjects in C++ I think.didierc

1 Answers

9
votes

If I understand your problem correctly, I would probably do something like this:

 bool WaitAndPop(T& value)
 {
    std::unique_lock<std::mutex> lk(mutex);            

    // Wait until the queue won't be empty OR stop is signaled
    condition.wait(lk, [&] ()
    {
        return (stop || !(myQueue.empty()));
    });

    // Stop was signaled, let's return false
    if (stop) { return false; }

    // An item was pushed into the queue, let's pop it and return true
    value = myQueue.front();
    myQueue.pop_front();

    return true;
}

Here, stop is a global variable like condition and myQueue (I suggest not to use queue as a variable name, since it is also the name of a Standard container adapter). The controlling thread can set stop to true (while holding a lock to mutex) and invoke notifyOne() or notifyAll() on condition.

This way, notify***() on the condition variable is invoked both when a new item is pushed into the queue and when the stop signal is being raised, meaning that a thread waking up after waiting on that condition variable will have to check for what reason it has been awaken and act accordingly.