老规矩,一张图胜过1000行注释。
#include <pthread.h>
pthread_cond_t cond=PTHREAD_COND_INITIALIZER
int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *cond_attr);
int pthread_cond_destroy(pthread_cond_t *cond);
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex);
int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);
int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);
APUE原文:
“ 调用者把锁住的互斥量传给函数,函数然后自动把调用线程放到等待条件的线程列表上,**对互斥量解锁。**这就关闭了条件检查和线程进入休眠状态等待条件改变这两个操作之间的时间通道,这样线程就不会错过条件的任何变化。pthread_cond_wait返回时,互斥量再次被锁住。”
也就是说,使用条件变量的前提是:线程、互斥锁。
起作用大概就是使多线程之间有交互、有限制地运行,防止线程不安全问题。
创建和初始化条件变量
pthread_mutex_t mtx; //互斥锁是必须的演猿
pthread_mutex_init(&mtx, NULL);
pthread_cond_t cond;
pthread_cond_init(&cond,NULL);
阻塞线程等待通知
while(条件不满足?)
{
pthread_cond_wait(&cond, &mtx);
}
pthread_cond_wait 函数一旦调用,则线程立即被阻塞,同时所拥有的互斥锁也被释放,线程一直停止在pthread_cond_wait 函数中,直到 pthread_cond_singal 函数通知对应的条件变量时接触阻塞,pthread_cond_wait 运行结束,但是返回的时会申请之前释放的互斥锁。
pthread_cond_timedwait 函数与 pthread_cond_wait 函数功能相同。不过多了一个超时参数。
超时值指定了我们愿意等待多长时间,如果超时到期之后,条件还是没有出现,此函数将重新获取互斥锁,然后返回错误 ETIMEOUT。
/* time.h
struct timespec
{
__time_t tv_sec; // 秒
long int tv_nsec; // 纳秒,1s = 1000*1000*1000ns
};
*/
struct timespec timeout;
timeout.tv_sec = time(NULL) + 1;//time(NULL);就是返回从1970年元旦午夜0点到现在的秒数,+1相当于等待1秒
timeout.tv_nsec = 0;
int err = pthread_cond_timedwait(&mtx, &timeout);
if(0 != err) { //没有获得锁
if(ETIMEDOUT == err) { //超时
......
}
}
唤醒信号发送
pthread_cond_signal(&cond);
pthread_cond_broadcast(&cond);
pthread_cond_signal 函数:至少能唤醒一个等待该条件的线程。
pthread_cond_broadcast 函数:则唤醒等待该条件的所有线程。
必须注意:最好是在改变条件状态以后再给线程发信号!!!wait 的写法多种多样,但是最常见的还是在 while 中,在 while 被唤醒的线程会因为不满足条件而再次被阻塞!!!
销毁条件变量
pthread_cond_destroy(&cond);
从用法上来看都可以推算出内部肯定是申请过内存的,既然是不再使用的内存就应该被释放掉。
案例
实验内容:控制两个线程打印出:A、B、A、B、A、B……
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
enum PRINK
{
A = 0,
B,
};
pthread_mutex_t mtx;
pthread_cond_t cond;
int flag;
void* A_thread()
{
while(1)
{
pthread_mutex_lock(&mtx);
while(flag == B)
{
pthread_cond_wait(&cond, &mtx);
}
FILE *fp = fopen( "test.txt", "a+" );
fputs("A", fp);
flag = B;
fclose( fp );
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mtx);
}
}
void* B_thread()
{
while(1)
{
pthread_mutex_lock(&mtx);
while(flag == A)
{
pthread_cond_wait(&cond, &mtx);
}
FILE *fp = fopen( "test.txt", "a+" );
fputs("B", fp);
flag = A;
fclose( fp );
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mtx);
}
}
int main(int argc, char **argv)
{
pthread_t th1;
pthread_t th2;
pthread_mutex_init(&mtx, NULL);
pthread_cond_init(&cond,NULL);
pthread_create(&th1,NULL,A_thread,NULL);
pthread_create(&th2,NULL,B_thread,NULL);
sleep(5);
pthread_cancel(th1);
pthread_cancel(th2);
}
运行结果:
最后发现了一个问题,使用 pthread_cond_t 的打印明显比 单独使用 pthread_mutex_t 多了很多。