• 信号量实现生产者消费者模型


    本实验的代码中采用的有界缓冲区拥有3个单元,每个单元为5字节。为了尽量体现每个信号量的意义,在程序中生产过程和消费过程是随机(采取0~5s的随机时间间隔)进行的,

    而且生产者的速度比比消费者的速度平均快两倍左右(这种关系可以相反)。生产者一次生产一个单元的产品(放入“hello”字符串),消费者一次消费一个单元的产品。

      1  /*本实验的代码中采用的有界缓冲区拥有3个单元,每个单元为5字节。
      2 *为了尽量体现每个信号量的意义,在程序中生产过程和消费过程是随机(采取0~5s的随机时间间隔)进行的,
      3 *而且生产者的速度比比消费者的速度平均快两倍左右(这种关系可以相反)。
      4 *生产者一次生产一个单元的产品(放入“hello”字符串),消费者一次消费一个单元的产品。
      5 */
      6 
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <string.h>
     10 #include <unistd.h>
     11 #include <fcntl.h>
     12 #include <errno.h>
     13 #include <pthread.h>
     14 #include <semaphore.h>
     15 #include <sys/ipc.h>
     16 #define MYFIFO    "./myfifo"
     17 #define BUFFER_SIZE    3
     18 #define UNIT_SIZE    6
     19 #define RUN_TIME    30
     20 #define DELAY_TIME_LEVELS    5.0
     21 
     22 int fd;    //管道描述符
     23 time_t end_time;    //存放线程的起始时间
     24 sem_t mutex,full,avail;    //信号量描述符
     25 
     26 //生产者线程
     27 void *producer(void *arg)
     28 {
     29     int real_write;        //实际写入字节数
     30     int delay_time=0;
     31 
     32     //time(MULL)返回从公元1970年1月1日的UC时间0时0分0秒算起
     33     //到现在所经过的描述,while()的意思就是说如果在执行生产者线程
     34     //的那一刻没有超过其结束时间,那么执行
     35     while(time(NULL)<end_time){
     36         //阐述0~5s的随机数
     37         delay_time=(int)(rand()*DELAY_TIME_LEVELS/(RAND_MAX)/2.0)+1;
     38         sleep(delay_time);
     39         //P操作信号量avail和mutex
     40         sem_wait(&avail);
     41         sem_wait(&mutex);
     42         printf("
    Producer: delay=%d
    ", delay_time);
     43         //生产者写入数据
     44         if((real_write=write(fd,"hello",UNIT_SIZE))==-1){
     45             //这个errno==EAGAIN表示的是你的write本来是非阻塞情况
     46             //表示现在没有数据可读,这个时候会置全局变量errno为
     47             //EAGINA,表示可以再次进行读操作;如果是阻塞情况,
     48             //那么被中断的话,errno=EINIR
     49             if(errno==EAGAIN){
     50                 printf("The FIFO has not been read yet. Please try later
    ");
     51             }
     52         }
     53         else{
     54             printf("wirte %d to the FIFO
    ", real_write);
     55         }
     56 
     57         //V操作信号量full和mutex
     58         sem_post(&full);
     59         sem_post(&mutex);
     60     }
     61     pthread_exit(NULL);
     62 }
     63 
     64 //消费者线程
     65 void *customer(void *arg)
     66 {
     67 //    unsigned int read_buffer[UNIT_SIZE];
     68     char read_buffer[UNIT_SIZE];
     69     int real_read;
     70     int delay_time;
     71 
     72     //time(MULL)返回从公元1970年1月1日的UC时间0时0分0秒算起
     73     //到现在所经过的描述,while()的意思就是说如果在执行生产者线程
     74     //的那一刻没有超过其结束时间,那么执行
     75     while(time(NULL)<end_time){
     76         //阐述0~5s的随机数
     77         delay_time=(int)(rand()*DELAY_TIME_LEVELS/(RAND_MAX)/2.0)+1;
     78         sleep(delay_time);
     79         //P操作信号量full和mutex
     80         sem_wait(&full);
     81         sem_wait(&mutex);
     82         memset(read_buffer,0,UNIT_SIZE);    //用0来初始化
     83         printf("
    Customer: delay=%d
    ", delay_time);
     84         //消费者消费数据
     85         if((real_read=read(fd,read_buffer,UNIT_SIZE))==-1){
     86             //这个errno==EAGAIN表示的是你的write本来是非阻塞情况
     87             //表示现在没有数据可读,这个时候会置全局变量errno为
     88             //EAGINA,表示可以再次进行读操作;如果是阻塞情况,
     89             //那么被中断的话,errno=EINIR
     90             if(errno==EAGAIN){
     91                 printf("No data yet
    ");
     92             }
     93         }
     94         else{
     95             printf("read %s from the FIFO
    ", read_buffer);
     96         }
     97 
     98         //V操作信号量avail和mutex
     99         sem_post(&avail);
    100         sem_post(&mutex);
    101     }
    102 }
    103 
    104 int main(int argc, char const *argv[])
    105 {
    106     pthread_t thrd_pro_id, thrd_cus_id;
    107     pthread_t mon_th_id;
    108     int ret;
    109 
    110     srand(time(NULL));    //随机数发生器初始化
    111     end_time=time(NULL)+RUN_TIME;
    112     //创建有名管道。若文件已存在,则mkfifo()返回errno=EEXIST
    113     if((mkfifo(MYFIFO, O_CREAT|O_EXCL)<0)&&(errno!=EEXIST)){
    114         printf("Cannot create fifo
    ");
    115         return errno;
    116     }
    117     //打开管道
    118     fd=open(MYFIFO,O_RDWR,0666);
    119     if(fd==-1){
    120         printf("Open fifo failed.
    ");
    121         return fd;
    122     }
    123 
    124     ret=sem_init(&mutex,0,1);
    125     ret+=sem_init(&avail,0,BUFFER_SIZE);
    126     ret+=sem_init(&full,0,0);
    127     if(ret!=0){    //这里ret用的倒也巧妙
    128         printf("Any semaphore initialization failed
    ");
    129         return ret;
    130     }
    131     
    132     //创建两个进程
    133     ret=pthread_create(&thrd_pro_id, NULL, (void *)producer, NULL);
    134     if(ret!=0){
    135         printf("create producer thread failed.
    ");
    136         return ret;
    137     }
    138     ret=pthread_create(&thrd_cus_id, NULL, (void *)customer, NULL);
    139     if(ret!=0){
    140         printf("create customer thread failed.
    ");
    141         return ret;
    142     }
    143     printf("wait for producer&customer thread
    ");
    144     pthread_join(thrd_pro_id,NULL);
    145     pthread_join(thrd_cus_id,NULL);
    146 //    unlink(MYFIFO);        //所有打开该文件的进程都结束时文件被删除
    147     return 0;
    148 }

    编译运行结果:

    然后我们看看myfifo文件,果然是权限有问题

     然后把文件的用户读权限加上去 chmod u+r myfifo ,就有结果啦

    但这终究不是办法呀,要是每次我都改一下权限那岂不是很麻烦,所以就只能该程序喽

    把113行 if((mkfifo(MYFIFO, O_CREAT|O_EXCL)<0)&&(errno!=EEXIST)) 改成 if((mkfifo(MYFIFO, O_CREAT|O_EXCL|0666)<0)&&(errno!=EEXIST)) 就可以啦。

    我们来看看效果,先删除原来的FIFO文件,重新编译,运行就有结果啦。

    我们来看看FIFO文件的权限

    好像跟我们设定的0666不太一样诶

    然后我们取消146行的注释看看

    果然运行完后不见myfifo

  • 相关阅读:
    curl获取HTTP返回状态码
    存储过程中如何实现从数组获取数据
    ElasticsearchParseException: malformed, expected settings to start with 'object', instead was [VALUE_STRING]
    【并发编程】如果让你用三个线程循环打印ABC,你有几种写法?
    【基础】IdentityHashMap
    【基础】ThreadPoolExecutor
    【算法】快速排序
    【Java8新特性Stream】list转map
    【算法】华为南研所-括号匹配
    windows sourceTree 密码错误
  • 原文地址:https://www.cnblogs.com/fallenmoon/p/6761513.html
Copyright © 2020-2023  润新知