理解条件变量的一个例子
看条件变量的时候将linux C 编程的例8-5代码抄了一遍,如下:
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
void * thread1(void *arg)
{
pthread_cleanup_push(pthread_mutex_unlock,&mutex);
while(1)
{
printf("thread1 is running\n");
pthread_mutex_lock (&mutex);
pthread_cond_wait (&cond,&mutex);
printf("thread1 applied the condition\n");
pthread_mutex_unlock (&mutex);
sleep(1);
}
pthread_cleanup_pop(0);
}
void * thread2(void *arg)
{
while(1)
{
printf("thread2 is running\n");
pthread_mutex_lock(&mutex);
pthread_cond_wait (&cond,&mutex);
printf("thread2 applied the condition\n");
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
int main(void)
{
int num=0;
pthread_t tid1,tid2;
printf("condition variable study!\n");
pthread_mutex_init (&mutex,NULL);
pthread_cond_init (&cond,NULL);
pthread_create(&tid1,NULL,(void *)thread1,NULL);
pthread_create(&tid2,NULL,(void *)thread2,NULL);
do
{
pthread_cond_signal(&cond); //给等待的线程发信号
}while(1);
sleep(50);
pthread_exit(0);
}
然后将执行结果重定义到一个 .txt 文档里,几分钟后回头一看,呆了,这程序居然还在运行。显然这就是一个死循环,之后就开始找哪出了问题。
有点坑啊!看了半天没看懂条件变量在这里有什么作用,自然根据这个程序就没理解了条件变量这一块内容。
还是去问问度娘吧。看了好几个关于条件变量介绍的网页,总算理解的差不多了。
下面是测试自己想法的时候根据书上那个例子改的程序,感觉比书上那个好理解:
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
pthread_mutex_t mutex;
pthread_cond_t cond;
int flag=0;
void * thread1(void *arg)
{
pthread_cleanup_push(pthread_mutex_unlock,&mutex);
for(flag=0;flag<=10;flag++)
{
printf("thread1 is running\n");
pthread_mutex_lock (&mutex);
if(flag%2==0)
pthread_cond_signal(&cond);//阻塞,通知正在等待此条件为真的线程
else
printf("flag of thread1 = %d\n",flag);
pthread_mutex_unlock (&mutex);
sleep(1);
}
pthread_cleanup_pop(0);
}
void * thread2(void *arg)
{
while(flag<10)
{
printf("thread2 is running\n");
pthread_mutex_lock(&mutex);
if(flag%2!=0)
{
pthread_cond_wait (&cond,&mutex);//等待glag%2==0的信号
}
printf("flag of thread2 = %d\n",flag);
pthread_mutex_unlock(&mutex);
sleep(1);
}
}
int main(void)
{
int num=0;
pthread_t tid1,tid2;
printf("condition variable study!\n");
pthread_mutex_init (&mutex,NULL); //初始化互斥锁
pthread_cond_init (&cond,NULL); //初始化条件变量
pthread_create(&tid1,NULL,(void *)thread1,NULL);//线程tid 1
pthread_create(&tid2,NULL,(void *)thread2,NULL);//线程tid 2
sleep(11);
pthread_mutex_destroy(&mutex);//清除互斥锁
pthread_cond_destroy(&cond); //清除条件变量
}
输出结果:
condition variable study!
thread2 is running
thread1 is running
flag of thread2 = 0
thread2 is running
thread1 is running
flag of thread1 = 1
thread1 is running
flag of thread2 = 2
thread1 is running
flag of thread1 = 3
thread2 is running
thread1 is running
flag of thread2 = 4
thread1 is running
flag of thread1 = 5
thread2 is running
thread1 is running
flag of thread2 = 6
thread1 is running
flag of thread1 = 7
thread2 is running
thread1 is running
flag of thread2 = 8
thread1 is running
flag of thread1 = 9
thread2 is running
thread1 is running
flag of thread2 = 10
从结果可以看出,上面的程序是用来划分0到10内的奇数和偶数的,线程1只输出奇数,线程2只负责输出偶数。
分析一下代码,看看条件变量扮演了什么角色:
线程1中,如果flag是偶数,调用pthread_cond_signal(&cond),这个函数会让当前进程阻塞,把条件为真的信号发给正在等待此信号的线程,告诉他“这个flag是偶数,交给你处理了”。如果是奇数,不发信号,输出flag。
与他对应的接受信号的是线程2,在线程2中,如果遇到flag不是偶数,那么调用
pthread_cond_wait (&cond,&mutex)线程阻塞,等待flag为偶数的信号传来唤醒进程后,才能继续执行剩下的语句。
说说 pthread_cond_wait ()是怎么工作的,执行这个函数时,他主要相当于做下面几个工作:
解锁----> 等待 ------>加锁
pthread_cond_wait 自动解锁互斥量(如同执行了 pthread_mutex_unlock),并等待条件变量触发。这时线程挂起,不占用 CPU 时间,直到条件变量被触发。pthread_cond_wait 函数返回前,自动重新对互斥量加锁(如同执行了 pthread_mutex_lock)。
使用 pthread_cond_wait ()之前必须使用pthread_mutex_lock()加锁,为什么呢? 这里要保证操作是原子性的,防止条件变量改变,如果不加锁,条件变量很可能被其他线程改变。那wait 函数之后为什么又要解锁,因为pthread_cond_wait ()在返回之前又给重新加了锁,所以函数调用完还要解锁。
pthread_cond_signal 使在条件变量上等待的线程中的一个线程重新开始。如果没有等待的线程,则什么也不做。如果有多个线程在等待该条件,只有一个能重启动,但不能指定哪一个。
哦,说下第一个程序为什么那么坑爹的死循环了:
主要是main函数里面 do { }while(1) 那两句导致的,主线程执行到这一段循环时,条件永真,会无休止的调用 pthread_cond_signal()给两个线程任意一个线程发信号,后面那sleep(50)根本没机会执行。有兴趣的话给do 里面再加几条语句,会发现结果更坑的。