线程同步实现方式
1. 条件变量(通互斥锁一起使用,互斥锁用来保护等待队列的)
2. 线程信号量
条件变量:
条件变量的内部是一个等待队列,这个队列中放置阻塞的线程,线程在这个队列中等待通知。
因为这个等待队列也时一个共享资源,所以也要用一把互斥锁来保护,即对等待队列上锁。
队列中的线程等特定的条件发生,当条件不满足时,线程先进入阻塞状态,等待条件的发生。一旦其他的某个线程改变了条件,就可唤醒一个或多个阻塞的线程。
数据类型:pthread_cond_t
条件变量的创建和销毁:
参数:
cond:条件变量
attr:条件变量属性,和互斥锁属性类似
条件变量的等待:
将线程放入等待队列中
参数:
cond:条件变量
mutex:互斥锁
互斥锁是对条件变量cond保护
条件变量的通知和唤醒:
参数:
cond:条件变量
当条件满足时,线程通知等待的线程
signal是通知单个线程;broadcast是通知所有线程
pthread_cond_wait(cond,mutex)函数内部的流程:
#include <stdio.h> #include <pthread.h> #include <unistd.h> typedef struct { int res; int is_wait; pthread_cond_t cond;//条件变量也要和共享资源绑定 pthread_mutex_t mutex;//保护条件变量 }ResArg; void *cal_fn(void *arg) { ResArg *result = (ResArg *)arg; int i = 0; int sum = 0; for(i = 0;i <101; i++){ sum +=i; } result->res = sum; pthread_mutex_lock(&result->mutex); while(result->is_wait == 0){//判断是否调用了wait函数 pthread_mutex_unlock(&result->mutex); usleep(100); pthread_mutex_lock(&result->mutex);//这里阻塞是保证wait函数先调用 }
//pthread_mutex_lock(&result->mutex); 加锁在while外不行 pthread_mutex_unlock(&result->mutex); pthread_cond_broadcast(&result->cond);//每次都要先保证wait函数先执行,然后在调用broadcast (void *)0; }
//如果pthread_mutex_lock(&result->mutex);放在while外,会出现问题,有几率出现如下顺序:
//在cal_fn函数中先加锁,然后判断is_wait=0就会解锁并阻塞,然后get_fn得到的时间片只够调用加锁,这时is_wait还是为0;
//然后cal_fn再次获得时间片,进入循环会将get_fn函数中加的锁解掉(这是就是无锁的状态),然后cal_fn再进入延时阻塞,
//这时get_fn又获得时间片,将is_wait置为1,然后将获得的时间片用完,这时的is_wait为1了。
//cal_fn阻塞完后再次判断is_wait不等于0了,退出循环,然后再加锁、解锁,再调用broadcast(这样broadcast就在wait之前了,就不行)
void *get_fn(void *arg) { ResArg *result = (ResArg *)arg; pthread_mutex_lock(&result->mutex); result->is_wait = 1;//将这个flag和wait函数绑定,1:表示调用了wait函数;0:表示没调用wait函数 pthread_cond_wait(&result->cond,&result->mutex); pthread_mutex_unlock(&result->mutex);//unlock在wait函数后,因为wait函数内部有上了互斥锁 printf("reslt = %d\n",result->res); (void *)0; } int main(void) { int err; pthread_t cal,get; ResArg r; r.is_wait = 0; pthread_cond_init(&r.cond,NULL); pthread_mutex_init(&r.mutex,NULL); if(pthread_create(&cal,NULL,cal_fn,(void *)&r) != 0){ printf("cal pthread creat fail\n"); } if(pthread_create(&get,NULL,get_fn,(void *)&r) != 0){ printf("get pthread creat fail\n"); } pthread_join(cal,NULL); pthread_join(get,NULL); pthread_cond_destroy(&r.cond); pthread_mutex_destroy(&r.mutex); return 0; }