1.条件变量相关调用函数
#include<pthread.h>
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
//这两个函数返回值:0成功,否则返回错误编号
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
int pthread_cond_timewait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex, const struct timespec *restrict tsptr);
//这两个函数返回值:0成功,否则返回错误编号
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
//这两个函数返回值:0成功,否则返回错误编号
2.用法和原理及需要注意的问题总结
使用条件变量之前,必须先对其进行初始化。由pthread_cond_t数据类型表示的条件变量可以用两种方式进行初始化,可以把常量PTHREAD_COND_INITIALIZER赋给静态分配的条件变量,但是如果条件变量是动态分配,则需要使用pthread_cond_init函数对其进行初始化。这里的静态分配方法是指在定义条件变量的时候直接用PTHREAD_COND_INITIALIZER进行赋值:
//正确
pthread_cond_t cond = PTHREAD_COND_ININTIALIZER;
//错误
pthread_cond_t cond;
cond = PTHREAD_COND_ININTIALIZER;
//正确
pthread_cond_t cond;
pthread_cond_init(&cond, NULL);
下面从一个一般性的条件变量的使用例子进行一步一步分析,洞悉条件变量使用的基本技巧和设计原则:
#include<pthread.h>
#include<time.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXBUFFER 1024
int ret;
char *mq = NULL;
pthread_t tid;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *thread_proc(void *lparam);
int main(int argc, char *argv[])
{
ret = pthread_create(&tid, NULL, thread_proc, NULL);
if(0 != ret){
return 0;
}
pthread_mutex_lock(&mutex);
while(NULL == mq)
pthread_cond_wait(&cond, &mutex);
//TODO:mq
printf("%s\n", mq);
pthread_mutex_unlock(&mutex);
return 0;
}
void *thread_proc(void *lparam)
{
pthread_mutex_lock(&mutex);
mq = (char *)malloc(MAXBUFFER);
memset(mq, 0, MAXBUFFER);
strcat(mq, "the condition is complete.");
pthread_mutex_unlock(&mutex);
pthread_cond_signal(&cond);
return ((void *)0);
}
上面代码是条件变量使用的一般的结构框架,条件mq在子线程分配存储空间(即所谓条件状态的改变),主线程需要及时探测到条件状态的改变并将mq存储的字符串信息打印出来。这里要注意一点是:pthread_cond_signal函数发给条件的信号必须在函数pthread_cond_wait将调用线程置为cond wait状态后才会被处理,否则将会被丢弃并且pthread_cond_wait函数会一直阻塞。试想如果没有锁住的互斥量的保护,mq条件判断时子线程还未开辟内存,因此继续执行循环体,pthread_cond_wait函数会先将线程置为cond wait状态,如果在pthread_cond_wait函数执行过程之前也就是主线程还未进入cond wait状态,子线程已经调用pthread_cond_signal发送信号,那么这个信号将会被丢弃,当主线程执行到pthread_cond_wait并置为cond wait状态后将一直阻塞,那么这个条件状态的改变就没有被探测到。《UNIX环境高级编程》上面对此有一句话的总结:传递给pthread_cond_wait的互斥量对条件进行保护。调用者把锁住的互斥量传给函数,函数然后自动把调用线程放入等待条件的线程列表上,对互斥量解锁。这就关闭了条件检查和线程进入休眠状态等待条件改变这两个操作之间的时间通道,这样过程就不会错过条件的任何变化。pthread_cond_wait函数返回时互斥量再次被锁住。