views:

1032

answers:

4

I'm looking for a way to wait for multiple condition variables. ie. something like:

boost::condition_variable cond1;  
boost::condition_variable cond2;

void wait_for_data_to_process()  
{  
    boost::unique_lock<boost::mutex> lock(mut);

    wait_any(lock, cond1, cond2); //boost only provides cond1.wait(lock);

    process_data();
}

Is something like this possible with condition variables. And if not are there alternative solutions?

Thanks

A: 
alternative solutions?

I am not sure of Boost library but you can use WaitForMultipleObjects Function to wait for multiple kernel objects. Just check if this helps.

aJ
Yeah i know of WaitForMultipleObject. I'm looking for the equivalent in boost. But it seems boost doesn't provide one. See: http://lists.boost.org/Archives/boost/2004/12/77175.php
+3  A: 

I don't believe you can do anything like this with boost::thread. Perhaps because POSIX condition variables don't allow this type of construct. Of course, Windows has WaitForMultipleObjects as aJ posted, which could be a solution if you're willing to restrict your code to Windows synchronization primitives.

Another option would to use fewer condition variables: just have 1 condition variable that you fire when anything "interesting" happens. Then, any time you want to wait, you run a loop that checks to see if your particular situation of interest has come up, and if not, go back to waiting on the condition variable. You should be waiting on those condition variables in such a loop anyways, as condition variable waits are subject to spurious wakeups (from boost::thread docs, emphasis mine):

void wait(boost::unique_lock<boost::mutex>& lock)
...
Effects:
Atomically call lock.unlock() and blocks the current thread. The thread will unblock when notified by a call to this->notify_one() or this->notify_all(), or spuriously. ...

Managu
It seems to me that having a third condition variable for "either 1 or 2 changed" is indeed the best approach. Another approach is to convert wait on condition into wait on file descriptors using select, and use pipes for for thread communication. Since this question is generic (it does not explain what things are been waited on), it's not clear that select will be better.
Vladimir Prus
A: 

As Managu points out using multiple conditions might not be a good solution in the first place. What you want to do should be possible to be implemented using Semaphores.

count0
+1  A: 

As Managu already answered, you can use the same condition variable and check for multiple "events" (bool variables) in your while loop. However, concurrent access to these bool variables must be protected using the same mutex that the condvar uses.

Since I already went through the trouble of typing this code example for a related question, I'll repost it here:

boost::condition_variable condvar;
boost::mutex mutex;
bool finished1 = false;
bool finished2 = false;

void longComputation1()
{
    {
        boost::lock_guard<boost::mutex> lock(mutex);
        finished1 = false;
    }
    // Perform long computation
    {
        boost::lock_guard<boost::mutex> lock(mutex);
        finished1 = true;
    }
    condvar.notify_one();
}

void longComputation2()
{
    {
        boost::lock_guard<boost::mutex> lock(mutex);
        finished2 = false;
    }
    // Perform long computation
    {
        boost::lock_guard<boost::mutex> lock(mutex);
        finished2 = true;
    }
    condvar.notify_one();
}

void somefunction()
{
    // Wait for long computations to finish without "spinning"
    boost::lock_guard<boost::mutex> lock(mutex);
    while(!finished1 && !finished2)
    {
        condvar.wait(lock);
    }

    // Computations are finished
}
Emile Cormier