三、条件变量。 1、 什么是条件变量? 线程因为某一个条件/情况不成立下,进入一个变量中等待,这个存放线程的变量就是条件变量。 条件变量一定要与互斥锁连用。
2、条件变量的函数接口。 1)先定义一个条件变量。 -> 数据类型: pthread_cond_t pthread_cond_t cond;
2)初始化条件变量。 -> pthread_cond_init() -> man 3 pthread_cond_init 动态初始化: 头文件: #include <pthread.h>
原型: int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
参数: cond: 条件变量的地址。 cond_attr: 普通属性,填NULL。
返回值: 成功:0 失败:非0
静态初始化: pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
3)如何进入条件变量中等待? -> pthread_cond_wait() -> man 3 pthread_cond_wait 头文件: #include <pthread.h>
原型: int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
参数: cond:条件变量的地址。 mutex: 互斥锁的地址。 -> 进入条件变量中等待时,会自动解锁。
返回值: 成功:0 失败:非0
4)如何唤醒条件变量中等待的线程? -> 线程离开条件变量时,会自动上锁。 广播:唤醒所有在条件变量中等待的线程。 --> pthread_cond_broadcast() 单播:随机唤醒一个在条件变量中等待的线程。 --> pthread_cond_signal()
头文件: #include <pthread.h>
原型: int pthread_cond_broadcast(pthread_cond_t *cond); int pthread_cond_signal(pthread_cond_t *cond);
参数: cond:条件变量的地址。
返回值: 成功:0 失败:非0
5)销毁条件变量。 -> pthread_cond_destroy() -> man 3 pthread_cond_destroy 头文件: #include <pthread.h>
原型: int pthread_cond_destroy(pthread_cond_t *cond);
参数: cond:条件变量的地址。
返回值: 成功:0 失败:非0
练习4: 有5个小孩,每一个小孩任务都是拿200块,首先在银行卡里面存400块,有2个小孩可以拿到钱后退出,3个线程拿不到钱就进去条件变量中睡眠,5S再打400块之后,唤醒所有的小孩起来拿钱,4S再打200块,唤醒一个小孩起来。
#include "head.h"
//初始化互斥锁 pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
//初始化条件变量 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
int sum = 400;
//线程: void *fun(void *arg) { //1. 每一个线程访问临界资源(银行卡)之前,都必须先上锁。 pthread_mutex_lock(&m); //2. 询问条件是否满足? while(sum < 200) //请问余额是不是<200 { //3. 不能拿到钱就进去睡眠。 pthread_cond_wait(&cond,&m); }
//4. 能拿到钱就扣钱 printf("before money:%d\n",sum); sum -= 200; printf("after money:%d\n",sum); //5. 解锁 pthread_mutex_unlock(&m); //6. 走人 pthread_exit(NULL); }
void *func_time(void *arg) { int i; for(i=0;i<100;i++) { printf("i = %d\n",i); sleep(1); } }
int main(int argc,char *argv[]) { //0. 倒数时间线程 pthread_t tid_time; pthread_create(&tid_time,NULL,func_time,NULL); //1. 由于5个线程任务一样,通过循环去创建线程。 int i; pthread_t tid[5]; for(i=0;i<5;i++) { pthread_create(&tid[i],NULL,fun,NULL); } //2. 打400块 sleep(5); pthread_mutex_lock(&m); sum += 400; printf("main thread + 400!\n"); pthread_mutex_unlock(&m); //3. 唤醒所有小孩 sleep(2); pthread_cond_broadcast(&cond); //只有2个小孩能拿到钱 //4. 打200块 sleep(3); pthread_mutex_lock(&m); sum += 200; printf("main thread + 200!\n"); pthread_mutex_unlock(&m);
//5. 唤醒一个小孩 sleep(2); pthread_cond_signal(&cond); //6. 接合线程 for(i=0;i<5;i++) { pthread_join(tid[i],NULL); } //7. 销毁资源 pthread_mutex_destroy(&m); pthread_cond_destroy(&cond); return 0; }