多线程-条件变量
条件变量 std::condition_variable,类似Linux C中的pthread_cond_t
可以用来阻塞当前线程,等待其他线程通知解除阻塞
condition_variable
std::condition_variable 条件变量类
void condition_variable::wait(unique_lock<mutex>&) / (unique_lock<mutex>& lck, Predicate pred)
//阻塞当前线程,两个参数的重载函数:设置了条件,有当 pred 条件为 false 时调用 wait() 才会阻塞当前线程,并且在收到其他线程的通知后只有当 pred 为 true 时才会被解除阻塞
//pred是一个bool返回值的函数
bool condition_variable::wait_for(unique_lock<mutex>&, chrono::duration)
bool condition_variable::wait_until(unique_lock<mutex>&, chrono::time_point)
//阻塞当前线程,加入超时控制,超过设置的时间,线程也结束阻塞
//wait_for是指定时间长度,wait_until是指定时间点
//这两个函数都有带设置条件的重载,当超时时:即使条件为false也会结束阻塞,当未超时:和wait函数的判断逻辑一致
//如果是超时退出的,则返回false;接收到通知或满足条件退出的,返回true
condition_variable::notify_all()
//通知所有线程解除阻塞
condition_variable::notify_one()
//通知一个线程解除阻塞,具体是哪个没法控制
std::condition_variable示例:
#include <iostream>
#include <thread>
#include <mutex>
#include <chrono>
#include <condition_variable>
std::mutex lmutex;
std::condition_variable cond;
bool flag1=false;
bool seq_func() {
return flag1;
}
void func1() {
std::unique_lock<std::mutex> lck(lmutex);
std::cout << "func1 before wait" << std::endl;
//线程阻塞,但这时不会占用lck,等结束阻塞后lck状态会恢复之前的状态
cond.wait(lck);
std::cout << "func1 after wait" << std::endl;
}
void func2() {
std::unique_lock<std::mutex> lck(lmutex);
std::cout << "func2 before wait" << std::endl;
//判断seq_func返回值,若为false,则阻塞线程;否则不阻塞
//线程阻塞时不会占用lck,等结束阻塞后lck状态会恢复之前的状态
//接收到通知后,判断seq_func的返回值,若为true,结束阻塞;否则继续阻塞
cond.wait(lck, seq_func);
std::cout << "func2 after wait" << std::endl;
}
void func3() {
std::unique_lock<std::mutex> lck(lmutex);
std::cout << "func3 before wait" << std::endl;
//设置超时时间1s,超时则结束阻塞
//如果在时间内收到解除阻塞通知,则要判断seq_func的返回值,为true退出,为false继续阻塞
bool stat = cond.wait_for(lck, std::chrono::seconds(1), seq_func);
std::cout << "func3 after wait, stat: " << stat << std::endl;
}
int main() {
std::thread th1(func1);
std::thread th2(func2);
std::thread th3(func3);
std::this_thread::sleep_for( std::chrono::seconds(10) );
//验证:经过延迟10s,线程1处于阻塞状态,但并未占用lmutex,主线程还可以获取锁
std::unique_lock<std::mutex> lck(lmutex);
std::cout << "main thread func " << std::endl;
std::this_thread::sleep_for( std::chrono::milliseconds(200) );
lck.unlock();
flag1 = true; //将条件置true
std::cout << "notify all" << std::endl;
cond.notify_all(); //通知所有线程,解除阻塞
th1.join();
th2.join();
th3.join();
return 0;
}
pthread_cond_xxx
《APUE》11章-线程
pthread_cond_xxx示例
/***
* 条件变量,配合互斥量使用。对互斥量进行条件保护
* pthread_cond_t 条件变量类型
* pthread_cond_init 初始化
* pthread_cond_wait/pthread_cond_timedwait 等待/超时等待条件变量的信号,等待时释放指定的互斥量,等待结束重新锁住互斥量
* pthread_cond_signal/pthread_cond_broadcast 向 至少一个/全部 等待该条件变量的线程发送信号
* pthread_cond_destroy 销毁
* *******/
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
typedef struct{
int age;
int count;
}PersonType;
pthread_cond_t qCond;
pthread_mutex_t qMutex;
void *pth_handler(void *arg){
//pthread_mutex_lock( &qMutex);
printf("cond wait start\n");
//把锁住的互斥量传入函数
pthread_cond_wait( &qCond, &qMutex); //等待条件变量信号,这时候不占用互斥量
//等wait函数返回时,互斥量再次被锁住
printf("cond wait done\n");
PersonType * p = arg;
p->count++;
p->age = 20;
//pthread_mutex_unlock( &qMutex);
pthread_exit(NULL);
}
int main(){
pthread_t pthid; //线程ID
PersonType p1 = {0,0};
pthread_mutex_init( &qMutex, NULL);
pthread_cond_init( &qCond, NULL); //初始化条件变量
if( 0 != pthread_create(&pthid, NULL, pth_handler, (void *)&p1)){
printf("pthread create failed\n");
}
sleep(1); //让刚才创建的线程先执行
//修改p1
printf("main sleep done\n");
pthread_mutex_lock( &qMutex);
p1.age = 10;
p1.count++;
printf("main change p\n");
pthread_mutex_unlock( &qMutex);
printf("cond signal\n");
//pthread_cond_signal( &qCond); //向至少一个等待该条件变量的线程发信号
pthread_cond_broadcast( &qCond); //向所有等待该条件变量的线程发信号
pthread_cond_destroy(&qCond);
pthread_mutex_destroy(&qMutex);
pthread_join( pthid, NULL);
printf("age = %d, count = %d\n", p1.age, p1.count);
}