【C/C++多執行緒程式設計之七】pthread訊號量

Love_Hulidear發表於2014-05-03

多執行緒程式設計之訊號量


     Pthread是 POSIX threads 的簡稱,是POSIX的執行緒標準
         互斥量用來處理一個共享資源的同步訪問問題,當有多個共享資源時,就需要用到訊號量機制。
         訊號量機制用於保證兩個或多個共享資源被執行緒協調地同步使用,訊號量的值對應當前可用資源的數量。

         1.訊號量samaphore):

        訊號量機制通過訊號量的值控制可用資源的數量。執行緒訪問共享資源前,需要申請獲取一個訊號量,如果訊號量為0,說明當前無可用的資源,執行緒無法獲取訊號量,則該執行緒會等待其他資源釋放訊號量(訊號量加1)。如果訊號量不為0,說明當前有可用的資源,此時執行緒佔用一個資源,對應訊號量減1。
        舉例:
        停車場有5個停車位,汽車可使用停車位。在這裡5個停車位是共享的資源,汽車是執行緒。開始訊號量為5,表明此時有5個停車位可用。一輛汽車進入停車場前,先查詢訊號量的值,不為0表明有可用停車位,汽車進入停車場並使用一個停車位,訊號量減1,表明佔用一個停車位,可用數減少。
       
           2.訊號量基本函式
         #include <semaphore.h>
初始化訊號量:
        int sem_init(sem_t *sem, int pshared, unsigned int val);
        該函式第一個引數為訊號量指標,第二個引數為訊號量型別(一般設定為0),第三個為訊號量初始值。第二個引數pshared為0時,該程式內所有執行緒可用,不為0時不同程式間可用。
訊號量減1:
        int sem_wait(sem_t *sem);
        該函式申請一個訊號量,當前無可用訊號量則等待,有可用訊號量時佔用一個訊號量,對訊號量的值減1。
訊號量加1:
        int sem_post(sem_t *sem);
        該函式釋放一個訊號量,訊號量的值加1。
銷燬訊號量:
        int sem_destory(sem_t *sem);
        該函式銷燬訊號量。       

        3.牛刀小試
        採用訊號量機制,解決蘋果橙子問題:一個能放N(這裡N設為3)個水果的盤子,爸爸只往盤子裡放蘋果,媽媽只放橙子,女兒只吃盤子裡的橙子,兒子只吃蘋果。
        採用三個訊號量:
        1.sem_t empty:訊號量empty控制盤子可放水果數,初始為3,因為開始盤子為空可放水果數為3。
        2.sem_t  apple ;訊號量apple控制兒子可吃的蘋果數,初始為0,因為開始盤子裡沒蘋果。
        3.sem_t orange;訊號量orange控制女兒可吃的橙子是,初始為0,因為開始盤子裡沒橙子。
注:互斥量work_mutex只為printf輸出時能夠保持一致,可忽略。
 
#include 
#include 
#include 
#include 
#pragma comment(lib, "pthreadVC2.lib")     //必須加上這句
sem_t empty;  //控制盤子裡可放的水果數
sem_t apple;  //控制蘋果數
sem_t orange; //控制橙子數
pthread_mutex_t work_mutex;                    //宣告互斥量work_mutex
void *procf(void *arg) //father執行緒
          { 
             while(1){
                 sem_wait(&empty);     //佔用一個盤子空間,可放水果數減1
                 pthread_mutex_lock(&work_mutex);     //加鎖
                 printf("爸爸放入一個蘋果!\n");
                 sem_post(&apple);     //釋放一個apple訊號了,可吃蘋果數加1
                 pthread_mutex_unlock(&work_mutex);   //解鎖
                 Sleep(3000);
             }

           }
void *procm(void *arg)  //mother執行緒
          { 
            while(1){
                sem_wait(&empty);
                pthread_mutex_lock(&work_mutex);     //加鎖
                printf("媽媽放入一個橙子!\n");
                sem_post(&orange);
                pthread_mutex_unlock(&work_mutex);   //解鎖
                Sleep(4000);
            }
           }
void *procs(void *arg)  //son執行緒
          { 
            while(1){
                sem_wait(&apple);       //佔用一個蘋果訊號量,可吃蘋果數減1 
                pthread_mutex_lock(&work_mutex);     //加鎖
                printf("兒子吃了一個蘋果!\n");
                sem_post(&empty);       //吃了一個蘋果,釋放一個盤子空間,可放水果數加1
                pthread_mutex_unlock(&work_mutex);   //解鎖
                Sleep(1000);
            }
           }
void *procd(void *arg)  //daughter執行緒
          { 
            while(1){
                sem_wait(&orange);
                pthread_mutex_lock(&work_mutex);     //加鎖
                printf("女兒吃了一個橙子!\n");
                sem_post(&empty);
                pthread_mutex_unlock(&work_mutex);   //解鎖
                Sleep(2000);
            }

           }

void main()
{ 
    pthread_t father;  //定義執行緒
    pthread_t mother;
    pthread_t son;
    pthread_t daughter;

    sem_init(&empty, 0, 3);  //訊號量初始化
    sem_init(&apple, 0, 0);
    sem_init(&orange, 0, 0);
	pthread_mutex_init(&work_mutex, NULL);   //初始化互斥量

    pthread_create(&father,NULL,procf,NULL);  //建立執行緒
    pthread_create(&mother,NULL,procm,NULL);
    pthread_create(&daughter,NULL,procd,NULL);
    pthread_create(&son,NULL,procs,NULL);

    Sleep(1000000000);
}


相關文章