耿小渣的進階之路
阿新 • • 發佈:2018-12-18
#include <stdio.h> #include <stdlib.h> #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); //這個mutex主要是用來保證pthread_cond_wait的併發性 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; }