condition_varible
# condition_variable
<condition_variable>头文件提供了条件变量的定义。其作为基本同步机制,允许被阻塞的线程在某些条件达成或超时时,解除阻塞继续执行。
namespace std
{
enum class cv_status { timeout, no_timeout };
class condition_variable;
class condition_variable_any;
}
# std::condition_variable类
std::condition_variable 允许阻塞一个线程,直到条件达成。
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false; // 全局标志位
void printId(int id)
{
std::unique_lock<std::mutex> lck(mtx);
// 如果标志位不为true,则等待
while(!ready)
{
// 线程被阻塞,直到标志位变为true
cv.wait(lck);
}
std::cout << "thread: " << std::this_thread::get_id() << " id: " << id << "\n";
}
void go()
{
std::unique_lock<std::mutex> lck(mtx);
// 改变全局标志位
ready = true;
// 唤醒所有线程
cv.notify_all();
}
int main()
{
std::thread threads[10];
for (int i = 0; i < 10; ++i)
{
threads[i] = std::thread(printId, i);
}
std::cout << "create done.\n" ;
go();
for (auto &t : threads)
{
t.join();
}
std::cout << "process done.\n" ;
return 0;
//输出:
create done.
thread: 140496261539584 id: 0
thread: 140496253146880 id: 1
thread: 140496244754176 id: 2
thread: 140496227968768 id: 4
thread: 140496211183360 id: 6
thread: 140496194397952 id: 8
thread: 140496202790656 id: 7
thread: 140496186005248 id: 9
thread: 140496219576064 id: 5
thread: 140496236361472 id: 3
process done.
wait 操作 std::condition_variable 提供了两种 wait() 函数。
无条件等待 void wait (unique_lock
& lck); 当前线程调用 wait() 后将被阻塞(此时当前线程应该获得了锁(mutex),不妨设获得锁 lck),直到另外某个线程调用 notify_* 唤醒了当前线程。在线程被阻塞时(也就是调用 wait() 的时候),该函数会自动调用 lck.unlock() 释放锁,使得其他被阻塞在锁竞争上的线程得以继续执行。另外,一旦当前线程获得通知(notified,通常是另外某个线程调用 notify_* 唤醒了当前线程),wait() 函数也是自动调用 lck.lock(),使得 lck 的状态和 wait 函数被调用时相同。 有条件等待 template
void wait (unique_lock & lck, Predicate pred); 第二种情况设置了 Predicate,只有当 pred 条件为 false 时调用 wait() 才会阻塞当前线程,并且在收到其他线程的通知后只有当 pred 为 true 时才会被解除阻塞。因此第二种情况类似以下代码:
while (!pred()) { wait(lck); } 和 mutex 的 lock 类似,std::condition_variable 也提供了相应的两种(带 Predicate 和不带 Predicate) wait_for() 函数,与 std::condition_variable::wait() 类似,不过 wait_for 可以指定一个时间段,在当前线程收到通知或者指定的时间超时之前,该线程都会处于阻塞状态。而一旦超时或者收到了其他线程的通知,wait_for 返回,剩下的处理步骤和 wait() 类似。还有 wait_util(),用法也类似。
notify 操作
std::condition_variable::notify_one() 唤醒某个等待(wait)线程。如果当前没有等待线程,则该函数什么也不做,如果同时存在多个等待线程,则唤醒某个线程是不确定的(unspecified)。
std::condition_variable::notify_all() 唤醒所有的等待(wait)线程。如果当前没有等待线程,则该函数什么也不做。
非常好文:https://blog.csdn.net/KingOfMyHeart/article/details/118076229
# std::condition_variable_any类
与 std::condition_variable 类似,只不过 std::condition_variable_any 的 wait 函数可以接受任何 lockable 参数,而 std::condition_variable 只能接受 std::unique_lockstd::mutex 类型的参数,除此以外,和 std::condition_variable 几乎完全一样。
int main()
{
std::queue<int> production;
std::mutex mtx;
std::condition_variable cv;
bool ready = false; // 是否有产品可供消费
bool done = false; // 生产结束
std::thread producer(
[&] () -> void {
for (int i = 1; i < 10; ++i)
{
// 模拟实际生产过程
std::this_thread ::sleep_for(std::chrono::milliseconds(10));
std::cout << "producing " << i << std::endl;
std::unique_lock<std::mutex> lock(mtx);
production.push(i);
// 有产品可以消费了
ready = true;
cv.notify_one();
}
// 生产结束了
done = true;
}
);
std::thread consumer(
[&] () -> void {
std::unique_lock<std::mutex> lock(mtx);
// 如果生成没有结束或者队列中还有产品没有消费,则继续消费,否则结束消费
while(!done || !production.empty())
{
// 防止误唤醒
while(!ready)
{
cv.wait(lock);
}
while(!production.empty())
{
// 模拟消费过程
std::cout << "consuming " << production.front() << std::endl;
production.pop();
}
// 没有产品了
ready = false;
}
}
);
producer.join();
consumer.join();
return 0;
}