這兩個函數是多線程操作中非常重要的,也是相對來說難理解的。這裏梳理一下。
首先是函數介紹,
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。
梳理了一遍流程,感覺對線程間的理解更清晰了一些。