linux下多線程互斥量實現生產者--消費者問題和哲學家就餐問題


生產者消費者問題,又有界緩沖區問題。兩個進程共享一個一個公共的固定大小的緩沖區。其中一個是生產者,將信息放入緩沖區,另一個是消費者,從緩沖區中取信息。

問題的關鍵在於緩沖區已滿,而此時生產者還想往其中放入一個新的數據的情況。其解決辦法是讓生產者睡眠,待消費者從緩沖區中取出一個或多個數據時再喚醒它,同樣的, 當消費者試圖從緩沖區中取數據而發現緩沖區空時,消費者就睡眠,直到消費者向其中放一些數據后再將其喚醒。

上述方法可以用互斥量解決,程序代碼:

  1 #include<sys/types.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<stdio.h>
  5 #include<pthread.h>
  6 #include<semaphore.h>
  7 
  8 //消費者進程
  9 void *thread_consumer(void *ptr); 
 10 //生產者進程
 11 void *thread_producer(void *ptr);
 12 
 13 #define MAX 100000   /*生產者需要生產的數量*/
 14 pthread_mutex_t the_mutex;  /*互斥量*/
 15 pthread_cond_t condc,condp;/*生產者和消費者的線程條件變量*/
 16 
 17 //初始時緩沖區中沒有數據
 18 int buffer=0;
 19 
 20 
 21 int buffer_max=0;/*用於記錄緩沖區最多被用了多少*/
 22 
 23 #define BUFFER_SIZE 10000    /*緩沖區大小*/
 24 
 25 /*消費者線程*/
 26 void *thread_consumer(void *arg)
 27 {
 28     int i;
 29     //消費完指定數目 退出線程
 30     for(i=0;i<MAX;i++)
 31     {
 32         //互斥量加鎖,線程同步
 33         pthread_mutex_lock(&the_mutex);
 34         /*緩沖區空  該進程睡眠   睡眠時pthread_cond_wait函數會對互斥量the_mutex解鎖,這樣生產者線程可以正常工作*/
 35         while(buffer==0)
 36         {
 37             pthread_cond_wait(&condc,&the_mutex);
 38         }
 39         //緩沖區非空 此時pthread_cond_wait又會對互斥量再次加鎖
 40         --buffer;  //消耗一個元素
 41         printf("consume an element, buffer=%d\n",buffer);  //打印緩沖區中剩余元素
 42         //如果緩沖區中元素個數為0   喚醒生產者線程
 43         if(buffer==0)
 44         {
 45             pthread_cond_signal(&condp);
 46         }
 47         //釋放互斥量
 48         pthread_mutex_unlock(&the_mutex);
 49     }
 50     pthread_exit(NULL);
 51 }
 52 
 53 /*生產者線程*/
 54 void *thread_producer(void *ptr)
 55 {
 56     int i;
 57      //消費完指定數目 退出線程
 58     for(i=0;i<MAX;i++)
 59     {
 60          //互斥量加鎖,線程同步
 61          pthread_mutex_lock(&the_mutex);
 62           //緩沖區滿, 該進程睡眠 睡眠時pthread_cond_wait函數會對互斥量the_mutex解鎖,這樣消費者線程可以正常工作*/
 63          while(buffer==BUFFER_SIZE)
 64          {
 65              pthread_cond_wait(&condp,&the_mutex);
 66          }
 67          // 緩沖區未滿時 此時pthread_cond_wait又會對互斥量再次加鎖
 68          ++buffer;//生產者增加一個數據
 69          /*記錄緩沖區最大的數據個數*/
 70          if(buffer>buffer_max)
 71                 buffer_max=buffer;
 72          printf("produce an element, buffer=%d\n",buffer);
 73          //如果緩沖區中元素個數大於0   喚醒消費者線程
 74          if(buffer>0)
 75          {
 76              pthread_cond_signal(&condc);
 77          }
 78          //釋放互斥量
 79          pthread_mutex_unlock(&the_mutex);
 80     }
 81 }
 82 
 83 int main()
 84 {
 85     pthread_t pro,con;
 86     //初始化互斥量
 87     pthread_mutex_init(&the_mutex,0);
 88     //初始化線程條件變量
 89     pthread_cond_init(&condc,0);
 90     pthread_cond_init(&condp,0);
 91     //創建生產者、消費者兩個線程
 92     pthread_create(&con,NULL,thread_consumer,NULL);
 93     pthread_create(&pro,NULL,thread_producer,NULL);
 94     //等待兩個線程結束
 95     pthread_join(pro,0);
 96     pthread_join(con,0);
 97     //清除變量
 98     pthread_cond_destroy(&condc);
 99     pthread_cond_destroy(&condp);
100     pthread_mutex_destroy(&the_mutex);
101     printf("buffer_max=%d",buffer_max);
102 }

在linux下運行時,可以看到兩個線程交替運行,為了看到緩沖區最大能被添加到多少,我把緩沖區大小設置的很大,這樣每次運行程序,打印的緩沖區的最大數都是不一樣的,這跟實際的線程調度有關。

 

科學家就餐問題:

問題描述:假設有五位哲學家圍坐在一張圓形餐桌旁,做以下兩件事情之一:吃飯,或者思考。吃東西的時候,他們就停止思考,思考的時候也停止吃東西。餐桌中間有一大碗意大利面,每兩個哲學家之間有一只餐叉。因為用一只餐叉很難吃到意大利面,所以假設哲學家必須用兩只餐叉吃東西。他們只能使用自己左右手邊的那兩只餐叉。哲學家就餐問題有時也用米飯和筷子而不是意大利面和餐叉來描述,因為很明顯,吃米飯必須用兩根筷子。用下面的圖描述很現實

問題解決:每個哲學家對應一個線程,程序中定義一個互斥量,對於每個線程進行訪問其他哲學家狀態時(關鍵代碼)用互斥量進行加鎖,這樣也就避免了死鎖的產生,訪問到該哲學家處於飢餓時,同時旁邊兩位科學家並未處於進餐狀態時,他就拿起左右兩邊的叉子進行吃飯,吃飯一段時間后,就放下叉子進行思考,思考一段時間后處於飢餓狀態,重新開始試圖拿起叉子吃飯,代碼如下:

#include<sys/types.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>
#include<time.h>
#define N 5     //哲學家數量

#define LEFT(i)    (i+N-1)%N  //左手邊哲學家編號
#define RIGHT(i)   (i+1)%N    //右手邊哲家編號

#define HUNGRY    0     //飢餓
#define THINKING  1     //思考
#define EATING    2     //吃飯

#define U_SECOND 1000000   //1秒對應的微秒數
pthread_mutex_t mutex;     //互斥量

int state[N];  //記錄每個哲學家狀態
//每個哲學家的思考時間,吃飯時間,思考開始時間,吃飯開始時間
clock_t thinking_time[N], eating_time[N], start_eating_time[N], start_thinking_time[N];  
//線程函數
void *thread_function(void *arg);

int main()
{
    pthread_mutex_init(&mutex, NULL);
    
    pthread_t a,b,c,d,e;
    //為每一個哲學家開啟一個線程,傳遞哲學家編號
    pthread_create(&a,NULL,thread_function,"0");
    pthread_create(&b,NULL,thread_function,"1");
    pthread_create(&c,NULL,thread_function,"2");
    pthread_create(&d,NULL,thread_function,"3");
    pthread_create(&e,NULL,thread_function,"4");
    //初始化隨機數種子
    srand((unsigned int)(time(NULL)));
    while(1)
    {
        ;
    }
}

void *thread_function(void *arg)
{
    char *a = (char *)arg;
    int num = a[0] - '0';  //根據傳遞參數獲取哲學家編號
    int rand_time; 
    while(1)
    {
        //關鍵代碼加鎖
        pthread_mutex_lock(&mutex);
        //如果該哲學家處於飢餓  並且  左右兩位哲學家都沒有在吃飯  就拿起叉子吃飯
        if(state[num] == HUNGRY && state[LEFT(num)] != EATING && state[RIGHT(num)] != EATING)
        {
            state[num] = EATING;
            start_eating_time[num] = clock(); //記錄開始吃飯時間
            eating_time[num] = (rand() % 5 + 5) * U_SECOND;   //隨機生成吃飯時間
            //輸出狀態
            printf("state: %d %d %d %d %d\n",state[0],state[1],state[2],state[3],state[4]);
            //printf("%d is eating\n",num);
        }
        else if(state[num] == EATING)
        {
            //吃飯時間已到 ,開始思考
            if(clock() - start_eating_time[num] >= eating_time[num])  //
            {
                state[num] = THINKING;
                //printf("%d is thinking\n",num);
                printf("state: %d %d %d %d %d\n",state[0],state[1],state[2],state[3],state[4]);
                start_thinking_time[num] = clock();  //記錄開始思考時間
                thinking_time[num] = (rand() % 10 + 10) * U_SECOND;  //隨機生成思考時間
            }
        }
        else if(state[num] == THINKING)
        {
            //思考一定時間后,哲學家餓了,需要吃飯
            if(clock() - start_thinking_time[num] >= thinking_time[num])
            {
                state[num] = HUNGRY;
                printf("state: %d %d %d %d %d\n",state[0],state[1],state[2],state[3],state[4]);
               // printf("%d is hungry\n",num);
            }
        }
        pthread_mutex_unlock(&mutex);       
    } 
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM