Reputation: 13369
I found an example code which demonstrates how to use a condition variable :
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <deque>
using namespace std;
deque<int> qu;
mutex mu;
condition_variable cond;
void fun1()
{
int count = 100;
while (count > 0)
{
unique_lock<mutex> locker(mu);
qu.push_front(count);
locker.unlock(); // explicit unlock 1
cond.notify_one();
--count;
}
}
void fun2()
{
int data = 0;
while(data != 1)
{
unique_lock<mutex> locker(mu);
cond.wait(locker, [](){ return !(qu.empty()); });
data = qu.back();
qu.pop_back();
locker.unlock(); // explicit unlock 2
cout<<"data: "<<data<<endl;
}
}
int main()
{
thread t1(fun1);
thread t2(fun2);
t1.join();
t2.join();
system("pause");
return 0;
}
I think that explicitly calling unlock is not necessary. However in fun1 calling it before notify_one might increase a performace, right ? Why unlock is called in fun2 (in each iteration unlock is called implicitly, so doing it explicitly make no sense) ?
Upvotes: 1
Views: 923
Reputation: 4272
It seems misleading to me. Locking with a mutex is required to use condition variables. This example uses the same mutex for multiple shared variables (cond
and qu
).
I think, it will not work properly if fun1
or fun2
runs on more than one thread.
Below would be more clear:
mutex mu;
mutex mu_for_cv;
condition_variable cond;
void fun1()
{
int count = 100;
while (count > 0)
{
unique_lock<mutex> locker(mu);
qu.push_front(count);
{
unique_lock<mutex> locker(mu_for_cv);
cond.notify_one();
}
--count;
}
}
void fun2()
{
int data = 0;
while(data != 1)
{
{
unique_lock<mutex> locker(mu_for_cv);
cond.wait(locker, [](){ return !(qu.empty()); });
}
unique_lock<mutex> locker(mu);
if (!qu.empty())
{
data = qu.back();
qu.pop_back();
cout<<"data: "<<data<<endl;
}
}
}
Also, it'd be better to check the queue is not empty in fun2
to defense against spurious wakeups.
Upvotes: -1
Reputation: 10733
std::unique_lock use the RAII pattern.
That means its doesn't need to explicitly call unlock on mutex. This provides exception safety i.e in case of exception after locking the mutex and before explicitly unlocking it it automatically gets unlocked as it goes out of scope.
Upvotes: 2