条件变量是用来通知共享数据状态信息的。
1.条件变量初始化两种方式:
(1)静态初始化
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
代码示例如下:
#include <pthread.h> typedef struct my_struct_tag { pthread_mutex_t mutex; /* Protects access to value */ pthread_cond_t cond; /* Signals change to value */ int value; /* Access protected by mutex */ } my_struct_t; my_struct_t data = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0}; int main (int argc, char *argv[]) { return 0; }
(2)动态初始化
int pthread_cond_init(pthread_cond_t *cond,pthread_condattr_t *condattr);
int pthread_cond_destroy(pthread_cond_t *cond);
代码示例如下:
#include <pthread.h> typedef struct my_struct_tag { pthread_mutex_t mutex; /* Protects access to value */ pthread_cond_t cond; /* Signals change to value */ int value; /* Access protected by mutex */ } my_struct_t; int main (int argc, char *argv[]) { my_struct_t *data; int status; data = malloc (sizeof (my_struct_t)); status = pthread_mutex_init (&data->mutex, NULL); status = pthread_cond_init (&data->cond, NULL); status = pthread_cond_destroy (&data->cond); status = pthread_mutex_destroy (&data->mutex); (void)free (data); return status; }
2.等待条件变量
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond,pthread_mutex_t *mutex,struct timespec *expiration);
当线程等待条件变量时,它必须将相关互斥量锁住。在阻塞线程之前,条件变量等待操作将解锁互斥量,而在重新返回线程之前,会再次锁住互斥量。
3.唤醒条件变量
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
在发送信号时也必须锁住互斥量,如果互斥量不被锁住,任何线程可以在被唤醒线程之前锁住互斥量。这将是一个产生被拦截唤醒的根源。例如,一个低优先级的线程可能锁住了互斥量,使高优先级的线程无法被其他线程唤醒,延迟了高优先级线程的调度。
4.需要在等待条件变量线程被唤醒后,检测条件
(1)被拦截的唤醒:等待条件变量被唤醒并加锁相关互斥量,若一个其他线程获得了互斥量,它可能在等待之前先检查条件。由于条件为真,所以它不需等待,直接处理工作,当它解锁时,已经没有可做的工作了。我们的第一个等待条件变量线程加锁互斥量后,再次检测条件,很有必要。
(2)松散的条件:使用不确定的条件时,循环检测条件,代码会更加健壮。
(3)假唤醒:在某些多处理器系统,会发生假唤醒的情况。
5.使用示例
主线程等待条件信号2S,子线程睡眠1S,改变共享数据值,发送信号,主线程接收信号,继续运行。
#include<stdio.h> #include<pthread.h> #include<errno.h> typedef struct cond_tag { pthread_mutex_t mutex; pthread_cond_t cond; int valid; }cond_t; cond_t data = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER, 0 }; void *thread_route(void *arg) { sleep(1); pthread_mutex_lock(&data.mutex); data.valid = 1; pthread_cond_signal(&data.cond); pthread_mutex_unlock(&data.mutex); return NULL; } int main(void) { int status; pthread_t pid; pthread_create(&pid,NULL,thread_route,NULL); struct timespec timeout; timeout.tv_sec = time(NULL)+2; timeout.tv_nsec = 0; pthread_mutex_lock(&data.mutex); while(data.valid==0) { status = pthread_cond_timedwait(&data.cond,&data.mutex,&timeout); if(status==ETIMEDOUT) { printf("wait timed out "); break; } } if(data.valid==1) { printf("cond is signaled "); } pthread_mutex_unlock(&data.mutex); return 0; }
参考资料:《POSIX多线程程序设计》 pp.59-74