一、条件变量函数
1,条件变量
条件变量:用来描述某种临界资源是否就绪的一种数据化描述。通常要配合mutex一起使用。
2,初始化
pthread_connd_init:
同样有一个静态的和一个动态的。
其中cond是需要初始化的条件变量,attr传nullptr。
3,销毁
pthread_cond_destroy;
cond:要销毁的条件变量。
4,等待
有俩个,一般只用第二个pthread_cond_wait:
在指定条件变量下等待。
这里需要传一个锁,这个起始很好理解,因为你等待一定是带着锁的,因为你首先抢到了锁了,准备执行你的任务,发现条件不满足,这时候你需要在自己的条件变量上等待,但是这个时候你自己是带着锁的,也就是说你在等待的时候别人不会再申请到锁了,所以你在等待的时候这个函数会自动释放你获得的锁,再你被唤醒时再去竞争锁。
条件等待是线程间同步的一种手段,如果只有一个线程,条件不满足,一直等下去都不会满足,所以必须要有一个线程通过某些操作,改变共享变量,使原先不满足的条件变得满足,并且友好的通知等待在条件变量上的线程。
条件不会无缘无故的突然变得满足了,必然会牵扯到共享数据的变化。所以一定要用互斥锁来保护。没有互斥锁就无法安全的获取和修改共享数据
5,唤醒
第一个是唤醒指定条件变量上面等待的一个进程,
第二个是唤醒指定条件变量上面等待的所有进程,
6,代码练习
#include <iostream>
#include <vector>
#include <functional>
#include <unistd.h>
#include <pthread.h>
using namespace std;
//创建一把静态的锁。
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
//创建一个条件变量
pthread_cond_t cond;
//相等于定义一个函数指针数组。
vector<function<void *()>> functors;
void *handler1()
{
cout << "handler1" << endl;
}
void *handler2()
{
cout << "handler2" << endl;
}
volatile bool quit = false;
void *waitcommend(void *args)
{
//线程分离。不需要等待了。
pthread_detach(pthread_self());
while (!quit)
{
//
pthread_mutex_lock(&mutex);
//不满足条件再这个条件变量上等待。
pthread_cond_wait(&cond, &mutex);
//被唤醒之后执行任务。
pthread_mutex_unlock(&mutex);
for (auto &e : functors)
{
e();
}
}
cout << "thread " << pthread_self() << "退出了" << endl;
return nullptr;
}
int main()
{
functors.push_back(handler1);
functors.push_back(handler2);
functors.push_back([]() -> void *
{ cout << "我是landan" << endl; });
//初始化条件变量
pthread_cond_init(&cond, nullptr);
pthread_t t1;
pthread_t t2;
pthread_t t3;
pthread_create(&t1, nullptr, waitcommend, nullptr);
pthread_create(&t2, nullptr, waitcommend, nullptr);
pthread_create(&t3, nullptr, waitcommend, nullptr);
sleep(3);
cout<<"设置退出标记位,唤醒全部线程"<<endl;
quit = true;//设置退出标记、
pthread_cond_broadcast(&cond);
while(true)
{
sleep(1);
cout<<"main runing "<<endl;
}
//销毁条件变量
pthread_cond_destroy(&cond);
while (true)
{
sleep(1);
cout << "我是main" << endl;
}
return 0;
}
开始条件不满足,全部再cond条件变量上面等待,然后设计标记位quit位true模拟条件满足,唤醒所有线程,执行代码后条件木满足不在等待线程不在等待,直接执行后续代码退出。