linux網絡編程-posix條件變量(40)
舉一個列子來說明條件變量:
假設有兩個線程同時訪問全局變量n,初始化值是0,
一個線程進入臨界區,進行互斥操作,線程當n大於0的時候才執行下面的操作,如果n不大於0,該線程就一直等待。
另外一個線程也是進入臨界區,修改n的值,當修改了n的值後,需要向等待中的線程發送通知,修改了n的值。但是現在存在這樣的一個問題:當第一個線程進入臨界區的時候,第一個線程一直處在等待n改變的狀態,第二個線程是無法進入臨界區的修改n的值的,這樣第一個線程
就處於死鎖了。上面這個問題可以時候條件變量來解決。
條件變量也可以用於生產者和消費者的狀態:
假設一個線程訪問一個隊列該隊列是空的,那麽該線程只能處於阻塞狀態,直到其他線程將一個產品添加到隊列中,發現通知通知等待的線程
對於等待條件的代碼,首先需要鎖定互斥量,因為這個條件變量是多個線程都可以同時訪問的,所以需要進行互斥,這裏使用while 等待只要條件為假,該線程就一直處於等待狀態
對於給條件發現信號的代碼:首先也是需要進行互斥,然後設置條件為真,然後給等待的線程發一個通知
下面我們使用條件變量來進行生產者與消費者的問題
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
pthread_cond_init函數可以用來初始化一個條件變量。他使用變量attr所指定的屬性來初始化一個條件變量,如果參數attr為空,那麽它將使用缺省的屬性來設置所指定的條件變量。
pthread_cond_destroy函數可以用來摧毀所指定的條件變量,同時將會釋放所給它分配的資源。調用該函數的進程也並不要求等待在參數所指定的條件變量上。
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex);
cond 條件變量
mutex 互斥鎖
第一個參數*cond是指向一個條件變量的指針。第二個參數*mutex則是對相關的互斥鎖的指針。
int pthread_cond_signal(pthread_cond_t *cond);
int pthread_cond_broadcast(pthread_cond_t *cond);
參數*cond是對類型為pthread_cond_t 的一個條件變量的指針。當調用pthread_cond_signal時一個在相同條件變量上阻塞的線程將被解鎖。如果同時有多個線程阻塞,則由調度策略確定接收通知的線程。如果調用pthread_cond_broadcast,則將通知阻塞在這個條件變量上的所有線程。一旦被喚醒,線程仍然會要求互斥鎖。如果當前沒有線程等待通知,則上面兩種調用實際上成為一個空操作。如果參數*cond指向非法地址,則返回值EINVAL。
#include <unistd.h> #include <sys/types.h> #include <pthread.h> #include <semaphore.h> #include <stdlib.h> #include <stdio.h> #include <errno.h> #include <string.h> #define ERR_EXIT(m) do { perror(m); exit(EXIT_FAILURE); } while(0) #define CONSUMERS_COUNT 1 #define PRODUCERS_COUNT 1 #define BUFFSIZE 10 //首先定義一個條件變量 pthread_cond_t g_cond; unsigned short in = 0; unsigned short out = 0; unsigned short produce_id = 0; unsigned short consume_id = 0; int nReady = 0;//表示當前產生的數目的計數器 pthread_mutex_t g_mutex; pthread_t g_thread[CONSUMERS_COUNT + PRODUCERS_COUNT]; void *consume(void *arg) { int i; int num = (int)arg; while (1) { // 首先需要進行互斥 pthread_mutex_lock(&g_mutex); while(nReady == 0){//等待產品不為空 //條件變量需要和互斥鎖進行配合使用 printf("consume thread_id %d now is waiting for .....\n",num); pthread_cond_wait(&g_cond,&g_mutex); } printf("consume thread_id %d now is begin consume product \n",num); //消費產品,將產品數據減一 nReady = nReady -1; pthread_mutex_unlock(&g_mutex); sleep(1); } return NULL; } void *produce(void *arg) { int num = (int)arg; int i; while (1) { // 首先需要進行互斥 pthread_mutex_lock(&g_mutex); //開始生產產品 nReady = nReady +1; //發起通知 printf("producter thread_id %d now is singal for consume .....\n",num); pthread_cond_signal(&g_cond); pthread_mutex_unlock(&g_mutex); sleep(3); } return NULL; } int main(void) { int i; //初始化一個互斥鎖 pthread_mutex_init(&g_mutex, NULL); //初始化條件變量 pthread_cond_init(&g_cond,NULL); for (i = 0; i < CONSUMERS_COUNT; i++) pthread_create(&g_thread[i], NULL, consume, (void *)i); for (i = 0; i < PRODUCERS_COUNT; i++) pthread_create(&g_thread[CONSUMERS_COUNT + i], NULL, produce, (void *)i); for (i = 0; i < CONSUMERS_COUNT + PRODUCERS_COUNT; i++) pthread_join(g_thread[i], NULL); //銷毀互斥鎖 pthread_mutex_destroy(&g_mutex); //銷毀條件變量 pthread_cond_destroy(&g_mutex); return 0; }
編譯下代碼:
gcc product.c -o product -lpthread
運行代碼:
./product
代碼中生產者和消費者都只有一個線程
我們來看程序運行的結果:
linux網絡編程-posix條件變量(40)