条件变量
为什么需要条件变量:在多线程编程中仅使用互斥锁来完成互斥是不够用的,如以下情形:假设有两个线程 t1 和 t2,需要这个两个线程循环对一个共享变量 sum 进行自增操作,那么 t1 和 t2 只需要使用互斥量即可保证操作正确完成,线程执行代码如所示:
pthread_mutex_t sumlock= PTHREAD_MUTEX_INITIALIZER; void * t1t2(void) { pthread_mutex_lock(&sumlock); sum++; pthread_mutex_unlock(&sumlock); }
void * t3 (void) { pthread_mutex_lock(&sumlock); if (sum >= 100) { sum = 0; pthread_mutex_unlock(&sumlock); } else { pthread_mutex_unlock(&sumlock); usleep(100); } }以上代码存在以下问题:
1.Pthreads用pthread_cond_t类型的变量来表示条件变量。程序必须在使用pthread_cond_t变量之前对其进行初始化。
(1)静态初始化
对于静态分配的变量可以简单地将 PTHREAD_COND_INITIALIZER 赋值给变量来初
始化默认行为的条件变量。
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
(2)动态初始化
对动态分配或者不使用默认属性的条件变量来说可以使用pthread _cond_init()来初始化。
函数原型如下: int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
参数cond是一个指向需要初始化pthread_cond_t变量的指针,
参数attr传递NULL值时,pthread_cond_init()将 cond 初始化为默认属性的条件变量。
函数成功将返回0;否则返回一个非0的错误码。
静态初始化程序通常比调用pthread_cond_init()更有效,而且在任何线程开始执行之前,确保变量被执行一次。
以下代码示例了条件变量的初始化:
pthread_cond_t cond; int error; if (error = pthread_cond_init(&cond, NULL)) fprintf(stderr, "Failed to initialize cond : %s\n", strerror(error));2. 销毁条件变量
pthread_cond_t cond; int error; if (error = pthread_cond_destroy(&cond)) fprintf(stderr, "Failed to destroy cond : %s\n", strerror(error));
pthread_cond_wait()函数在条件不满足时将一直等待,而 pthread_cond_timedwait()将只等待一段时间。
参数cond是一个指向条件变量的指针,
参数mutex是一个指向互斥量的指针,线程在调用前应该拥有这个互斥量,
当线程要加入条件变量的等待队列时,等待操作会使线程释放这个互斥量。
pthread_timedwait()的第三个参数 abstime 是一个指向返回时间的指针,如果条件变量通知信号没有在此等待时间之前出现,等待将超时退出,abstime 是个绝对时间,而不是时间间隔。
以上函数成功调用返回0,否则返回非0的错误码,其中pthread_cond_timedwait()函数如果 abstime 指定的时间到期,错误码为 ETIMEOUT。
以下代码使得线程进入等待,直到收到通知并且满足 a 大于等于 b 的条件。
<span style="font-size:18px;">pthread_mutex_lock(&mutex); while(a < b) pthread_cond_wait(&cond, &mutex); pthread_mutex_unlock(&mutex) ;</span>
demo6:
#include<stdio.h> #include<string.h> #include<pthread.h> #include<stdlib.h> #include<unistd.h> pthread_t tid[3]; int sum = 0; pthread_mutex_t sumlock = PTHREAD_MUTEX_INITIALIZER;//静态初始化互斥量 pthread_cond_t cond_sum_ready = PTHREAD_COND_INITIALIZER;//静态初始化条件变量 void * t1t2(void *arg) { int i; long id = (long)arg; for (i = 0; i < 10; i++) { pthread_mutex_lock(&sumlock);//使用互斥量保护临界变量 sum++; printf("t%ld: read sum value = %d\n", id + 1 , sum); pthread_mutex_unlock(&sumlock); if (sum >= 10) pthread_cond_signal(&cond_sum_ready);//发送条件通知,唤醒等待进程 } return NULL; } void * t3(void *arg) { pthread_mutex_lock(&sumlock); while(sum < 10) pthread_cond_wait(&cond_sum_ready, &sumlock);//不满足条件一直等待 sum = 0; printf("t3: clear sum value\n"); pthread_mutex_unlock(&sumlock); return NULL; } int main(void) { int err; long i; for (i = 0; i < 2; i++) { //创建两个线程 err = pthread_create(&(tid[i]), NULL, &t1t2, (void *)i); if (err != 0) { printf("Can't create thread :[%s]", strerror(err)); } } err = pthread_create(&(tid[2]), NULL, &t3, NULL); if (err != 0) printf("Can't create thread :[%s]", strerror(err)); for (i = 0; i < 3; i++) pthread_join(tid[i], NULL);//阻塞等待线程退出 return 0; }