条件变量的优势
条件变量提供了一种线程间的通知机制,达到条件唤醒对应线程,配合互斥量,可以解决多线程中大多数的同步问题。需要信号量的解决问题的基本都可以用条件变量加互斥量解决。由于信号量使用起来容易出错,实际工程中用互斥量和条件变量的更多。
互斥量可以保护共享数据的原子访问,但是无法很好的保证条件时序,单纯使用非阻塞接口配合sleep调用的忙等待会浪费CPU,也无法做到第一时间感知到条件ok。这里配合条件变量就可以解决此场景了。一个典型的消费者线程先启动的场景的时序:
相关函数:
1.
名称: | pthread_cond_init |
目标: | 条件变量初始化 |
头文件: | #include < pthread.h> |
函数原形: | int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr); |
参数: | cptr 条件变量 attr 条件变量属性 |
返回值: | 成功返回0,出错返回错误编号。 |
pthread_cond_init函数可以用来初始化一个条件变量。他使用变量attr所指定的属性来初始化一个条件变量,如果参数attr为空,那么它将使用缺省的属性来设置所指定的条件变量。
2.
名称: | pthread_cond_destroy |
目标: | 条件变量摧毁 |
头文件: | #include < pthread.h> |
函数原形: | int pthread_cond_destroy(pthread_cond_t *cond); |
参数: | cptr 条件变量 |
返回值: | 成功返回0,出错返回错误编号 |
pthread_cond_destroy函数可以用来摧毁所指定的条件变量,同时将会释放所给它分配的资源。调用该函数的进程也并不要求等待在参数所指定的条件变量上。
3.
名称: | pthread_cond_wait/pthread_cond_timedwait |
目标: | 条件变量等待 |
头文件: | #include < pthread.h> |
函数原形: | int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex); int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t mytex,const struct timespec *abstime); |
参数: | cond 条件变量 mutex 互斥锁 |
返回值: | 成功返回0,出错返回错误编号。 |
第一个参数*cond是指向一个条件变量的指针。第二个参数*mutex则是对相关的互斥锁的指针。函数pthread_cond_timedwait函数类型与函数pthread_cond_wait,区别在于,如果达到或是超过所引用的参数*abstime,它将结束并返回错误ETIME.pthread_cond_timedwait函数的参数*abstime指向一个timespec结构。该结构如下:
typedef struct timespec{
time_t tv_sec;
long tv_nsex;
}timespec_t;
4.
名称: | pthread_cond_signal/pthread_cond_broadcast |
目标: | 条件变量通知 |
头文件: | #include < pthread.h> |
函数原形: | int pthread_cond_signal(pthread_cond_t *cond); int pthread_cond_broadcast(pthread_cond_t *cond); |
参数: | cond 条件变量 |
返回值: | 成功返回0,出错返回错误编号。 |
实验:有两条线程,一条用于设置数据,一条用于获取数据,当设置数据还未完成时,不能获取到数据
实验源码:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
typedef struct
{
int res;
int is_wait;
pthread_cond_t cond;
pthread_mutex_t mutex;
}Result;
void * func_set(void *arg)
{
Result *r=(Result *)arg;
int i=1,sum=0;
for(;i<=100;i++)
{
sum=sum+i;
}
r->res=sum;
printf("the pthread %lx has write done\n",pthread_self());
pthread_mutex_lock(&r->mutex);
while(!r->is_wait)
{
pthread_mutex_unlock(&r->mutex);
usleep(1000);
pthread_mutex_lock(&r->mutex);
}
pthread_mutex_unlock(&r->mutex);
printf("I am ready to broadcast\n");
pthread_cond_broadcast(&r->cond);
}
void *func_get(void *arg)
{
Result *r=(Result *)arg;
pthread_mutex_lock(&r->mutex);
r->is_wait=1;
pthread_cond_wait(&r->cond,&r->mutex);
printf("I have receive the infomation\n");
pthread_mutex_unlock(&r->mutex);
int res=r->res;
printf("the pthread %lx read the result is %d\n",pthread_self(),res);
}
int main(void)
{
int err;
pthread_t rabbit,turtle;
Result r;
r.is_wait=0;
pthread_mutex_init(&r.mutex,NULL);
pthread_cond_init(&r.cond,NULL);
if((err=pthread_create(&rabbit,NULL,func_set,(void *)&r))!=0)
{
perror("pthread_create error");
}
if((err=pthread_create(&turtle,NULL,func_get,(void *)&r))!=0)
{
perror("pthread_create error");
}
pthread_join(rabbit,NULL);
pthread_join(turtle,NULL);
pthread_mutex_destroy(&r.mutex);
pthread_cond_destroy(&r.cond);
printf("control thread id: %lx\n",pthread_self());
printf("finished!\n");
return 0;
}