1. 程式人生 > >Linux C:利用兩個執行緒實現生產者消費者模型

Linux C:利用兩個執行緒實現生產者消費者模型

在使用執行緒實現消費者生產者模型前,簡單介紹一下執行緒的概念。

執行緒是程序的一個實體,對於程序而言,程序是程式資源分配的最小單元,這在之前提及過;而對於執行緒,它是程式執行的最小單元,即CPU排程和分派的基本單位,它附屬於程序,同樣也能獨立執行。關於資源分配上,執行緒基本不擁有系統資源,只擁有執行中必不可少的一些資源如程式計數器,棧等。

對於執行緒同樣有互斥和同步問題,互斥是多個執行緒之間操作同個共享資料時使某個執行緒操作,而其他的執行緒阻塞,直到資源解鎖才能訪問。同步則是令執行緒間按一定的順序去執行。下面的模型就是採用同步機制使一個執行緒作為生產者,向全域性字元陣列寫入資料,而另一個執行緒作為消費者,從陣列中讀取資料,通過兩個訊號量的P、V操作實現兩執行緒的順序先後,兩者間為“先生產再消費”,即同步來實現。

具體實現程式碼如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>

#define TEXT_SZ 1024

sem_t sem1;
sem_t sem2;

char text[TEXT_SZ];

void *write(void *text) //生產者資料輸入函式
{

    while(1)
    {
        sem_wait(&sem1); //訊號量sem1 p操作
        printf("(producer) write some text:");
        if(fgets((char *)text, TEXT_SZ, stdin) == NULL) //寫資料到全域性陣列
        {
            printf("write error!\n");
            exit(1);
        }
        
        if(strncmp((char *)text,"end",3) == 0) //輸入end退出執行緒1
        {
            sem_post(&sem2); //訊號量sem2 v操作
            break;
        }

        sem_post(&sem2); //訊號量sem2 v操作
    }
}

void *read(void *text) //消費者讀取資料函式
{
    while(1)
    {
        sem_wait(&sem2); //訊號量sem2 p操作
        printf("(customer)  read  the text:%s\n",(char *)text); //輸出讀到的資料
        
        if(strncmp((char *)text,"end",3) == 0) //讀取到end,退出執行緒2
        {
            sem_post(&sem1); //訊號量sem1 v操作
            break;
        }

        sem_post(&sem1); //訊號量sem1 v操作
    }

}

int main()
{
    pthread_t thread1;
    pthread_t thread2;

    int ret1;
    int ret2;

    if(sem_init(&sem1,0,1) == -1) //初始化訊號量sem1
    {
        printf("init sem1 error!\n");
        exit(1);
    }


    if(sem_init(&sem2,0,0) == -1) //初始化訊號量sem2
    {
        printf("init sem2 error!\n");
        exit(1);
    }

    if(memset(text,0,sizeof(text)) == NULL)
    {
        printf("memset error!\n");
        exit(1);
    }

    ret1 = pthread_create(&thread1,NULL,(void *)write,(void *)text);//建立執行緒1
    if(ret1 < 0)
    {
        printf("thread1 create error!\n");
        exit(1);
    }

    ret2 = pthread_create(&thread2,NULL,(void *)read,(void *)text);//建立執行緒2
    if(ret2 < 0)
    {
        printf("thread2 create error!\n");
        exit(1);
    }

    pthread_join(thread1,NULL); //等待執行緒1退出
    pthread_join(thread2,NULL);//等待執行緒2退出
    
    if(sem_destroy(&sem1) == -1) //刪除訊號量sem1
    {
        printf("delete sem1 error!\n");
        exit(1);
    }
    
    if(sem_destroy(&sem2) == -1) //刪除訊號量sem2
    {
        printf("delete sem2 error!\n");
        exit(1);
    }

    return 0;
}