Reputation: 839
In Stroustrup's book The C++ Programming Language, there is a code example that demonstrates the use of condition variables:
class Message { // object to be communicated
//...
};
queue<Message> mqueue; // the queue of messages
condition_variable mcond; // the variable communicating events
mutex mmutex; // the locking mechanism
A producer writes to the queue, and a consumer reads it from the queue.
void producer()
{
while(true) {
Message m;
//... fill the message ...
unique_lock<mutex> lck {mmutex}; // protect operations
mqueue.push(m);
mcond.notify_one(); // notify
} // release lock (at end of scope)
}
The code for consumer:
void consumer()
{
while(true) {
unique_lock<mutex> lck{mmutex}; // acquire mmutex
mcond.wait(lck,[this]{ return !mqueue.empty(); }); // release lck and wait until not empty;
// re-acquire lck upon wakeup
auto m = mqueue.front(); // get the message
mqueue.pop();
lck.unlock(); // release lck
//... process m ...
}
}
I understand how this works. Could you explain the difference between this approach and an implementation using a semaphore? I reviewed this and this, but I’m still unclear on the distinctions in this specific case.
Is there anything wrong with an implementation with semaphore instead of condition variable?
Initialize counting semaphore as
std::counting_semaphore filled(0);
Producer code and consumer code :
void producer()
{
while (true)
{
Message m;
//... fill the message ...
{
std::scoped_lock lck(mmutex);
mqueue.push(m);
}
filled.release();
}
}
void consumer()
{
while (true)
{
filled.acquire();
{
std::scoped_lock lck(mmutex);
auto m = mqueue.front();
mQueue.pop();
// ... process m ....
}
}
}
I understand filled.release()
call in producer will keep incrementing the counter, if consumer code doesn't run. Other than that is there a problem with this code?
Does filled.acquire() have a busy-wait loop wasting CPU cycles? Even if it has, won't it break out of the loop as soon as the first Message is pushed by the producer?
Upvotes: 0
Views: 58