à背景知識介紹
1 互斥量
互斥量函數有
pthread_mutex_init 初始化一個互斥量
pthread_mutex_lock 給一個互斥量加鎖
pthread_mutex_trylock 加鎖,如果失敗不阻塞
pthread_mutex_unlock 解鎖
互斥量從本質上說是一把鎖,在訪問共用資源前對互斥量進行加鎖,在訪問完成後釋放互斥量上的鎖。對互斥量進行加鎖以後,任何其他試圖再次對互斥量加鎖的線程將會被阻塞直到當前線程釋放該互斥鎖。
2 條件變數
靜態方式使用PTHREAD_COND_INITIALIZER常量,如下:
pthread_cond_t cond=PTHREAD_COND_INITIALIZER
動態方式調用pthread_cond_init()函數,API定義如下:
pthread_cond_init
pthread_cond_wait無條件等待
ipthread_cond_timedwait 計時等待
pthread_cond_signal()啟用一個等待該條件的線程,存在多個等待線程時按入隊順序啟用其中一個
而pthread_cond_broadcast()則啟用所有等待線程。
條件變數實現的是一種通知機制,先線上程B中調用pthread_cond_wait(cond,mutex)等待條件變數被觸發而且在沒有被激發之前B就一直阻塞在pthread_cond_wait,一旦線上程A中調用pthread_cond_signal()從而激發條件變數,即通知線程B條件變數可用則B中中pthread_cond_wait由阻塞變成執行狀態(執行過程中mutex首先unlock->wait return->mutexlock )。
à互斥量和條件變數之間的關係
1 為了保證 線程A對條件變數可用的通知發出,線程B接收該通知的過程做到順序化。保證前一時刻有一個已經發出的條件變數可用通知之後,才讓B阻塞於pthread_cond_wait(為了實現這個,互斥量是個不錯的選擇)。
2如果沒有互斥量可能造成 thread_func訪問臨界資源時,main()也去訪問造成競爭。
à貼一個例子:
#include <pthread.h>#include <unistd.h>static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;struct node {int n_number;struct node *n_next;} *head = NULL;/*[thread_func]*/static void cleanup_handler(void *arg){ printf("Cleanup handler of second thread./n"); free(arg); (void)pthread_mutex_unlock(&mtx);}static void *thread_func(void *arg){ struct node *p = NULL; pthread_cleanup_push(cleanup_handler, p); while (1) { pthread_mutex_lock(&mtx); while (head == NULL) { //這個while要特別說明一下,單個pthread_cond_wait功能很完善,為何這裡要有一個while (head == NULL)呢?因為pthread_cond_wait裡的線程可能會被意外喚醒,如果這個時候head != NULL,則不是我們想要的情況。這個時候,應該讓線程繼續進入pthread_cond_wait pthread_cond_wait(&cond, &mtx); // pthread_cond_wait會先解除之前的pthread_mutex_lock鎖定的mtx,然後阻塞在等待對列裡休眠,直到再次被喚醒(大多數情況下是等待的條件成立而被喚醒,喚醒後,該進程會先鎖定先pthread_mutex_lock(&mtx);,再讀取資源 //用這個流程是比較清楚的/*block-->unlock-->wait() return-->lock*/ } p = head; head = head->n_next; printf("Got %d from front of queue/n", p->n_number); free(p); pthread_mutex_unlock(&mtx); //臨界區資料操作完畢,釋放互斥鎖 } pthread_cleanup_pop(0); return 0;}int main(void){ pthread_t tid; int i; struct node *p; pthread_create(&tid, NULL, thread_func, NULL); /*[tx6-main]*/ for (i = 0; i < 10; i++) { p = malloc(sizeof(struct node)); p->n_number = i; pthread_mutex_lock(&mtx); //需要操作head這個臨界資源,先加鎖, p->n_next = head; head = p; pthread_cond_signal(&cond); pthread_mutex_unlock(&mtx); //解鎖 sleep(1); } printf("thread 1 wanna end the line.So cancel thread 2./n"); pthread_cancel(tid); //關於pthread_cancel,有一點額外的說明,它是從外部終止子線程,子線程會在最近的取消點,退出線程,而在我們的代碼裡,最近的取消點肯定就是pthread_cond_wait()了。關於取消點的資訊,有興趣可以google,這裡不多說了 pthread_join(tid, NULL); printf("All done -- exiting/n"); return 0;}
http://blog.csdn.net/hairetz/article/details/4535920