条件变量是实现线程间同步的一种方法,条件变量用来自动阻塞一个线程,直到收到收到一个cond信号或其它特殊情况发送,条件变量使用的时候必须与互斥量同时使用,这是为了保证条件量在线程间操作的“原子性”。
1、创建一个条件变量cond:
int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr);
在初始化一个条件变量时如果attr为 NULL,测使用默认值初始化一个条件变量cond,相当于下面的方式定义一个条件变量cond;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
2、销毁一个条件变量cond:
int pthread_cond_destroy(pthread_cond_t *cond);
可以销毁一个条件变量cond,使其未初始化。一个被引用的条件变量是不可被销毁的,使用一个被销毁的条件变量将造成为止的后果,在默认条件下测试,将导致线程将直处于阻塞状态。
3、等待一个条件变量:
int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex, const struct timespec *restrict abstime);
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
将导致线程阻塞在条件变量cond,应用程序应确保被mutex锁定的线程调用这些函数,否则可能导致未知错误。
这两个函数在执行开始将自动释放mutex,等待条件变量之后将自动锁定mutex,如果有其它线程正在调用mutex将导致线程阻塞。具体执行过程如下所示:
pthread_mutex_cond_unlock(mutex);
pthread_cond_wait(cond);
pthread_mutex_cond_lock(mutex);
在包含pthread_cond_wait函数的线程结束前一定要释放mutex,否则可能会造成其它等待cond的线程一直阻塞。如果有其它线程获得了互斥锁mutex,也将导致cond的线程阻塞。
4、唤醒一个被cond阻塞的线程:
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
pthread_cond_signal将唤醒一个被阻塞的线程,pthread_cond_broadcast是唤醒所有被阻塞的线程,如果没有被阻塞的线程pthread_cond_signal与pthread_cond_broadcast也将正确返回,但是其产生的信号将不起任何作用。
5、使用pthread_cond_timedwait实现精确延时,在单个线程中的cond与mutex可以直接用下面方式实现精确延时:
void set_abswaittime(struct timespec*outtime, int ms)
{
long sec ;
long usec ;
struct timeval tnow;
gettimeofday(&tnow, NULL);
usec = tnow.tv_usec + ms*1000;
sec = tnow.tv_sec+usec/1000000;
outtime->tv_nsec=(usec%1000000)*1000;
outtime->tv_sec=sec;
}
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond=PTHREAD_COND_INITIALIZER; struct timespec abstime; set_abswaittime(&abstime,1000); pthread_cond_wait(&tcond, &tmutex, &abstime);
6、条件变量使用测试,测试代码如下:
// // 创建人: levy // 创建时间:May 25, 2017 // 功能:main.c // Copyright (c) 2016 levy. All Rights Reserved. // Ver 变更日期 负责人 变更内容 // ────────────────────────────────────────────────────────────────────────── // V0.01 May 25, 2017 levy 初版 // #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <time.h> #include <sys/time.h> #include <pthread.h> #include <string.h> #include <errno.h> pthread_mutex_t test_mutex=PTHREAD_MUTEX_INITIALIZER; pthread_cond_t test_cond=PTHREAD_COND_INITIALIZER; int test_count; void * test_thread1(void *arp) { int s=(int)arp; printf("I am thread %ld ,I will sleep %d s .\n",pthread_self(),s);
sleep(s); pthread_mutex_lock(&test_mutex); pthread_cond_wait(&test_cond,&test_mutex); test_count++; printf("my thread id is %ld ,testcount=%d \n",pthread_self(),test_count); pthread_mutex_unlock(&test_mutex); pthread_exit(NULL); } int main(void ) { pthread_t th[3]; test_count=0; for(int i=0;i<3;i++) { pthread_create(&th[i],NULL,test_thread1,i); } for(int i=0;i<3;i++) {
sleep(3); pthread_cond_signal(&test_cond); } for(int i=0;i<3;i++) { pthread_join(th[i],NULL); } pthread_exit(NULL); }
输出结果:
I am thread 140391800571648 ,I will sleep 1 s .
I am thread 140391808964352 ,I will sleep 1 s .
I am thread 140391792178944 ,I will sleep 1 s .
my thread id is 140391808964352 ,testcount=1
my thread id is 140391800571648 ,testcount=2
my thread id is 140391792178944 ,testcount=3
如有错误,谢谢指正!
更新:2017-06-02 15:54:50
参考资料:http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_broadcast.html#tag_16_418