pthread_cond_wait和pthread_cond_signal的使用方法梳理

这两个函数是多线程操作中非常重要的,也是相对来说难理解的。这里梳理一下。

首先是函数介绍,

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。

 

梳理了一遍流程,感觉对线程间的理解更清晰了一些。

 

 

 

 

上一篇:ALV 定时器


下一篇:leetcode刷题05