1. 程式人生 > >linux網絡編程-posix條件變量(40)

linux網絡編程-posix條件變量(40)

color 鎖定 需要 大於 amp com 編程 efi ....

技術分享

舉一個列子來說明條件變量:

假設有兩個線程同時訪問全局變量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)