Friday, May 31, 2013

condition variable pthread

Mutex cater to the most general form of resource sharing, but sometimes threads have more specific sharing requirements.Condition Variables allow us to express and control a directed dependency between threads. In general this means that one group of threads should only execute when a given condition becomes true, and this condition will be satisfied by another group of threads.
When thread operation is coordinated by a condition variable, one group of threads waits until a condition is triggered, at which point one or more of the waiting threads is woken.
An example: there are two groups of threads: one producing something, and the other consuming it. The Producer-Consumer pattern is also useful outside multi-threaded programming, where it allows you to decouple data/event/request/whatever production from consumption. For our contrived example, we produce and consume characters from the alphabet.
std::queue<char> producedChars;
 
boost::condition characterAvailable;
boost::mutex characterMutex;
 
void conditionDataProducer()
{
    unsigned char c = 'A';
    for(uint i = 0; i < numCharacters;)
    {
        if((c >= 'A' && c <= 'Z'))
        {
            boost::mutex::scoped_lock lock(characterMutex);
            producedChars.push(c++);
            characterAvailable.notify_one();
            ++i;
        }
        else
        {
            c = 'A';
        }
    }
    boost::mutex::scoped_lock lock(characterMutex);
    producedChars.push(EOF);
    characterAvailable.notify_one();
}
 
void conditionDataConsumer()
{
    boost::mutex::scoped_lock lock(characterMutex);
 
    while(true)
    {
        // on entry, releases mutex and suspends this thread
        // on return, reacquires mutex
        while(producedChars.empty())
        {
            characterAvailable.wait(lock);
        }
 
        if(producedChars.front() == EOF) break;
        producedChars.pop();
    }
}
Take a look at the consumer first: it acquires a mutex and then uses the condition variable to wait. When waitis called the mutex is unlocked and the calling thread is suspended. The consumer thread will now only be resumed when the condition represented by character Available becomes true.
The producer simply pushes characters onto the shared container and then calls notify_one. This will allow one of the threads waiting on this condition (a consumer) to resume and process the new data. This will be much more efficient than having consumers endlessly polling an empty queue.
Condition variables are also useful in implementing the Monitor Object concurrency pattern, which we talk about next.

See also:

No comments:

Post a Comment