初始化條件變量
int pthread_cond_init(pthread_cond_t *cv,pthread_cond_attr *cattr); 函數返回值:返回0表示成功,返回其他表示失敗。 參數: pthread_cond_attr是用來設置pthread_cond_t的屬性,當傳入的值是NULL的時候表示使用默認的屬性。
函數返回時,創建的條件變量保存在cv所指向的內存中,可以用宏PTHREAD_COND_INITIALIZER來初始化條件變量。值得注意的是不能使用多個線程初始化同一個條件變量,當一個線程要使用條件變量的時候確保它是未被使用的。
條件變量的銷毀
int pthread_cond_destroy(pthread_cond_t *cv); 返回值:返回0表示成功,返回其他值表示失敗。
條件變量的使用:
int pthread_cond_wait(pthread_cond_t *cv,pthread_mutex_t *mutex) int pthread_cond_signal(pthread_cond_t *cv);
使用方式如下:
pthread_mutex_lock(&mutex) while or if(線程執行的條件是否成立) pthread_cond_wait(&cond,&mutex); 線程執行 pthread_mutex_unlock(&mutex);
為什么要加鎖
- 線程在執行的部分訪問的是進程的資源,有可能多個線程需要訪問它,為了避免由於線程並發執行所引起的資源競爭,所以要讓每個線程互斥的訪問公共資源。
- 如果while或if判斷不滿足線程的執行條件時,線程回調用pthread_cond_wait阻塞自己。pthread_cond_wait被調用線程阻塞的時候,pthread_cond_wait會自動釋放互斥鎖。線程從調用pthread_cond_wait到操作系統把他放在線程等待隊列之后的時候釋放互斥鎖。
使用while和if判斷線程執行條件釋放成立的區別。
在多線程資源競爭的時候,在一個使用資源的線程里面(消費者)判斷資源是否可用,不可用便調用pthread_cond_wait,在另一個線程里面(生產者)如果判斷資源可用的話,則會調用pthead_cond_signal發送一個資源可用的信號。
但是在wait成功之后,資源就不一定可以被使用,因為同時有兩個或兩個以上的線程正在等待次資源,wait返回后,資源可能已經被使用了,在這種情況下
while(resource == FALSE) pthread_cond_wait(&cond,&mutex);
如果之后只有一個消費者,就可使用if。
分解pthread_cond_wait動作為以下步驟:
- 線程放在等待隊列上,解鎖
- 等待pthread_cond_signal或者pthread_cond_broadcast信號之后去競爭鎖
- 若競爭到互斥鎖則加鎖
有可能多個線程在等待這個資源可用的信號,信號發出去之后只有一個資源可用,但是有A,B兩個線程在等待,B速度比較快,獲得互斥鎖,然后加鎖,消耗資源,然后解鎖,之后A獲得互斥鎖,但它回去發現資源已經被使用了,它便有兩個選擇,一個失去訪問不存在的資源,另一個就是繼續等待,那么等待下去的條件就是使用while,要不然使用if的話pthread_cond_wait返回后,就會順序執行下去。
等待線程:
pthread_cond_wait 前要加鎖
pthread_cond_wait 內部會解鎖,然后等待條件變量被其他線程激活
pthread_cond_wait 被激活后會再自動加鎖
激活線程
加鎖(和等待線程用同一個鎖)
pthread_cond_signal 發送信號(階躍信號前最后判斷有無等待線程)
解鎖
激活線程的上面三個操作再運行時間上都是再等待線程的pthread_cond_wait函數內部。
/*** pthread_if.c ***/ #include<stdio.h> #include<sys/types.h> #include<stdlib.h> #include<unistd.h> #include<pthread.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int count = 0; void *decrement(void *arg) { printf("in derment\n"); pthread_mutex_lock(&mutex); if(count == 0) pthread_cond_wait(&cond,&mutex); count--; printf("----decrement:%d\n",count); printf("out decrement\n"); pthread_mutex_unlock(&mutex); return NULL; } void *increment(void *arg) { printf("in increment\n"); pthread_mutex_lock(&mutex); count++; printf("-----increment:%d\n",count); if(count != 0) { pthread_cond_signal(&cond); } printf("out increment\n"); pthread_mutex_unlock(&mutex); return NULL; } int main() { pthread_t tid_in,tid_de; pthread_create(&tid_de,NULL,(void*)decrement,NULL); sleep(1); pthread_create(&tid_in,NULL,(void*)increment,NULL); sleep(1); pthread_join(tid_de,NULL); pthread_join(tid_in,NULL); pthread_mutex_destroy(&mutex); pthread_cond_destroy(&cond); return 0; }
/*** pthread_while.c ***/ #include<stdio.h> #include<stdlib.h> #include<pthread.h> #include<unistd.h> typedef struct node_s { int data; struct node_s *next; }node_t; node_t *head = NULL; pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; void cleanup_handler(void *arg) { printf("cleanup_handler is running.\n"); free(arg); pthread_mutex_unlock(&mutex); } void *thread_func(void *arg) { node_t *p = NULL; pthread_cleanup_push(cleanup_handler,p); while(1) { pthread_mutex_lock(&mutex); while(NULL == head) pthread_cond_wait(&cond,&mutex); p = head; head = head->next; printf("process %d node\n",p->data); free(p); pthread_mutex_unlock(&mutex); } pthread_cleanup_pop(0); return NULL; } int main() { pthread_t tid; node_t *temp = NULL; int i; pthread_create(&tid,NULL,(void*)thread_func,NULL); for(i = 0; i < 10; i++) { temp = (node_t*)malloc(sizeof(node_t)); temp->data = i; pthread_mutex_lock(&mutex); temp->next = head; head = temp; pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); sleep(1); } pthread_cancel(tid); pthread_join(tid,NULL); return 0; }