这两个函数是多线程操作中非常重要的,也是相对来说难理解的。这里梳理一下。
首先是函数介绍,
int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
这里有两个参数,cond和mutex。cond是条件,这个值可以用宏做声明:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
也可以使用函数来声成:
int pthread_cond_init(pthread_cond_t *cond, pthread_cond_attr *cattr);
int pthread_cond_destroy(pthread_cond_t *cond);
第一个函数是init,第二个为destroy。函数中的cond便是条件变量。这里需要说下,第一个函数中的cattr是属性声明,一般用NULL使用默认属性,其属性在函数返回时,写道cond指向的内存。
另一个主角是:
int pthread_cond_signal(pthread_cond_t *cond)
这两个一般搭配使用,pthread_cond_wait将当前线程阻塞等待,而在调用pthread_cond_signal后,将再次激活。当然,还有其它一些函数搭配使用,看下面的例子。
#include<pthread.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//init mutex
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//init cond
void *thread1(void*);
void *thread2(void*);
int i = 1; //global
int main(void){
pthread_t p1;
pthread_t p2;//two thread
pthread_create(&p2,NULL,thread2,(void*)NULL);
pthread_create(&p1,NULL,thread1,(void*)NULL);//Create thread
pthread_join(p2,NULL);//wait a_b thread end
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
exit(0);
}
void *thread1(void *parameter){
for(i = 1;i<= 9; i++){
pthread_mutex_lock(&mutex); //互斥锁
printf("\n\ncall thread1 \n");
if(i%3 == 0)
{
pthread_cond_signal(&cond); //send sianal to p2
printf("p1:%d step1\n", i);
}
else
printf("p1:%d step2\n",i);
pthread_mutex_unlock(&mutex);
printf("p1: sleep i=%d step3\n", i);
sleep(1);
printf("p1: sleep i=%d step4\n", i);
}
}
void *thread2(void*parameter){
while(i < 9)
{
pthread_mutex_lock(&mutex);
printf("\n\ncall thread2 \n");
if(i%3 != 0)
pthread_cond_wait(&cond,&mutex); //wait signal from p1
printf("p2: %d step1\n",i);
pthread_mutex_unlock(&mutex);
printf("p2: sleep i=%d step2\n", i);
sleep(1);
printf("p2: sleep i=%d step3\n", i);
}
}
其运行结果为
call thread1
p1:1 step2
p1: sleep i=1 step3
call thread2
p1: sleep i=1 step4
call thread1
p1:2 step2
p1: sleep i=2 step3
p1: sleep i=2 step4
call thread1
p1:3 step1
p1: sleep i=3 step3
p2: 3 step1
p2: sleep i=3 step2
p1: sleep i=3 step4
call thread1
p1:4 step2
p1: sleep i=4 step3
p2: sleep i=4 step3
call thread2
p1: sleep i=4 step4
call thread1
p1:5 step2
p1: sleep i=5 step3
p1: sleep i=5 step4
call thread1
p1:6 step1
p1: sleep i=6 step3
p2: 6 step1
p2: sleep i=6 step2
p1: sleep i=6 step4
call thread1
p1:7 step2
p1: sleep i=7 step3
p2: sleep i=7 step3
call thread2
p1: sleep i=7 step4
call thread1
p1:8 step2
p1: sleep i=8 step3
p1: sleep i=8 step4
call thread1
p1:9 step1
p1: sleep i=9 step3
p2: 9 step1
p2: sleep i=9 step2
p1: sleep i=9 step4
p2: sleep i=10 step3
接下来,一点点解释。
第一阶段,call thread1=>p1:1 step2=>p1: sleep i=1 step3
首先因为p1优先级高,所以先call thread1,然后i%3!=0,所以运行p1:1 step2,接下来就是p1: sleep i=1 step3
需要注意的是,由于第三句话之前,已经pthread_mutex_unlock,解除了互斥锁,所以p2是可以访问共享资源了的。
在sleep 1秒的时间里,发生了第二阶段。
第二阶段:call thread2=>p1: sleep i=1 sep4
这里因为 i % 3 != 0, 所以执行了pthread_cond_wait,进入了等待阶段,p2后续的就先不运行。
这里需要注意,虽然p2也上了锁,但是pthread_cond_wait发挥了它的作用,将线程锁解开了。
这就是他的一个作用pthread_cond_wait,先会解除当前线程的互斥锁,然后挂线线程,等待条件变量满足条件。一旦条件变量满足条件,则会给线程上锁,继续执行pthread_cond_wait。
第三阶段:call thread1=>p1:3 step1.......
回到pthread1,只时候i已经循环到3了,所以执行了pthread_cond_signal,条件变量又满足了,所以p2的又被激活。
因此,打印出了p2: 3 step1=>p2: sleep i=3 step2。然后因为p2有解除了锁,在sleep时候,程序又切换到了p1线程。
后续的流程便是这样了。
最后一个阶段:
call thread1
p1:9 step1
p1: sleep i=9 step3
p2: 9 step1
p2: sleep i=9 step2
p1: sleep i=9 step4
p2: sleep i=10 step3
因为i已经到了9,不会再循环了,所以pthread1的最后一句便是p1: sleep i=9 step4。
但是,i还要再加1,所以传到p2的时候,最后一句就成了p2: sleep i=10 step3。
梳理了一遍流程,感觉对线程间的理解更清晰了一些。