• 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
    ",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
    ",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
    ",state[0],state[1],state[2],state[3],state[4]);
                //printf("%d is eating
    ",num);
            }
            else if(state[num] == EATING)
            {
                //吃饭时间已到 ,开始思考
                if(clock() - start_eating_time[num] >= eating_time[num])  //
                {
                    state[num] = THINKING;
                    //printf("%d is thinking
    ",num);
                    printf("state: %d %d %d %d %d
    ",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
    ",state[0],state[1],state[2],state[3],state[4]);
                   // printf("%d is hungry
    ",num);
                }
            }
            pthread_mutex_unlock(&mutex);       
        } 
    }
  • 相关阅读:
    自动添加控件,一次提交多条记录。
    Asp.Net 2.0 的 Master Page(母版页)
    vs2008中文版提供下载(包含中文msdn),包括vs2008序列号和破解方法。
    C# 2.0 :仿MSN提示框or仿迅雷提示框(.Net2.0).rar
    httpanalyzer 结合 HttpWebRequest Post的运用
    xp访问权限问题的解决(绝对有效)
    Request.params、Request、Request.querystring、Request.Form 具体区别!
    C# List<> 泛型中遍历不同类型
    备份与恢复数据库的存储过程
    .Net 生成不重复的随机数
  • 原文地址:https://www.cnblogs.com/yangang92/p/5414887.html
Copyright © 2020-2023  润新知