• POSIX信号量与互斥锁实现生产者消费者模型


    posix信号量 Link with -lpthread.

    sem_t *sem_open(const char *name, int oflag);//打开POSIX信号量
    sem_t *sem_open(const char *name, int oflag,mode_t mode, unsigned int value);

    int sem_init(sem_t *sem, int pshared, unsigned int value);

    posix互斥锁(第七章)
    int pthread_mutex_destroy(pthread_mutex_t *mutex);
    int pthread_mutex_init(pthread_mutex_t *restrict mutex,const pthread_mutexattr_t *restrict attr);
    pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

    有两个信号量。

    p操作:测试信号量值大于0,减1.sem_wait
    v操作:给定信号量值加1. sem_post
    用posix信号量和互斥锁解决生产者消费者问题
    一、生产者线程的任务:
    p(sem_full),p一个满的信号量(缓冲区容量),如果仓库还没满(sem_full>0),我们就能生产产品。一旦我们
    生产了一个产品,仓库既不是一个空的状态了,我们V一个空的信号量sem_empty.就告诉了消费者可以消费了。
    由于可能有多个生产者,所以引入一个互斥量。
    二:消费者的任务:
    要p(sem_empty),如果生产者没有V一个sem_empty,消费者p操作sem_empty可能就不行,所以要等生产者生产了产品,
    v了sem_empty通知到消费者,消费者才可以消费。一旦消费了一个产品,就可以V(sem_full)是的仓库容量减一(不满)通知
    到生产者线程又可以生产了。由于可能有多个消费者,所以引入一个互斥量。

    假设仓库容量为10,刚开始可以生产产品,所以sem_full(10)信号量初始值设为10,表示可以生产10个。
    刚开始仓库中没有产品可以消费,所以sem_empty(0)初始值为0.

      1 #include<unistd.h>
      2 #include<sys/types.h>
      3 #include<fcntl.h>
      4 #include<sys/stat.h>
      5 #include<stdlib.h>
      6 #include<stdio.h>
      7 #include<errno.h>
      8 #include <semaphore.h>
      9 #include<pthread.h>
     10 #define ERR_EXIT(m)
     11     do
     12     {
     13         perror(m);
     14         exit(EXIT_FAILURE);
     15     }while(0)
     16 #define CONSUMERS_COUNT  1    //消费者线程个数
     17 #define PRODUCERS_COUNT  2    //生产者线程个数
     18 #define BUFFSIZE 10              //缓冲区大小(仓库大小)
     19 int g_buffer[BUFFSIZE];       //环形缓冲区
     20 unsigned short in=0;        //初始生产产品放置位置
     21 unsigned short out=0;        //初始消费的产品位置
     22 unsigned short produce_id=0;//当前正在消费的产品ID
     23 unsigned short consume_id=0;//当前正在消费的产品ID
     24 //两个信号量,一个互斥锁。
     25 sem_t g_sem_full;//可生产产品的数量
     26 sem_t g_sem_empty;//可消费产品的数量
     27 pthread_mutex_t g_mutex;
     28 
     29 pthread_t  g_thread[CONSUMERS_COUNT+PRODUCERS_COUNT ];//线程ID.生产者线程个数+消费者线程个数
     30 //消费者线程执行的任内务
     31 void* consume(void*arg)
     32 {
     33     int num=(int)arg;
     34     int i;
         //消费者不断消费
    35 while(1) 36 { 37 printf("%d wait buffer not empty ",num); 38 //sem_wait测试信号量值大于0减一并立即返回.P操作 39 sem_wait(&g_sem_empty); 40 pthread_mutex_lock(&g_mutex); 41 //消费之前打印基本信息 42 for(i=0;i<BUFFSIZE;i++) 43 { 44 printf("%02d ",i);//仓库序号 45 if(g_buffer[i]==-1) 46 printf("%s ","null");//仓库为空 47 else 48 printf("%d ",g_buffer[i]); 49 if(i==out) 50 printf(" <--consume");//消费位置 51 printf(" "); 52 } 53 consume_id=g_buffer[out]; 54 printf("%d begin consume product %d ",num,consume_id); 55 g_buffer[out]=-1; 56 out=(out+1)%BUFFSIZE; 57 printf("%d end consume product %d ",num,consume_id); 58 pthread_mutex_unlock(&g_mutex); 59 //给定信号量值加1。V操作,消费了一个产品,仓库就可以再生产产品 60 sem_post(&g_sem_full); 61 sleep(1); 62 } 63 return NULL; 64 } 65 //生产者线程执行的任务。 66 void* produce(void*arg) 67 { 68 int num=(int)arg; 69 int i; 70 while(1) 71 { 72 printf("%d wait buffer not full ",num); 73 //sem_wait测试信号量值大于0减一并立即返回.g_sem_full代表可以生产的个数,生产了一个之后,可以生产的个数就要减一 74 //所以初始值为buffersize 75 sem_wait(&g_sem_full); 76 pthread_mutex_lock(&g_mutex); 77 //生产之前打印基本信息 78 for(i=0;i<BUFFSIZE;i++) 79 { 80 printf("%02d ",i);//仓库序号 81 if(g_buffer[i]==-1) 82 printf("%s ","null");//仓库为空 83 else 84 printf("%d ",g_buffer[i]); 85 if(i==in) 86 printf(" <--produce");//生产位置 87 printf(" "); 88 } 89 printf("%d begin produce product %d ",num,produce_id); 90 g_buffer[in]=produce_id; 91 in=(in+1)%BUFFSIZE; 92 printf("%d end produce product %d ",num,produce_id++); 93 pthread_mutex_unlock(&g_mutex); 94 //生产了一个产品的话,就给g_sem_empty信号量值加1 95 sem_post(&g_sem_empty); 96 sleep(5); 97 } 98 return NULL; 99 } 100 int main(void) 101 { 102 int i; 103 for(i=0;i<BUFFSIZE;i++) 104 g_buffer[i]=-1; 105 //初始化信号量 106 sem_init(&g_sem_full,0,BUFFSIZE); 107 sem_init(&g_sem_empty,0,0); 108 //初始化互斥量 109 pthread_mutex_init(&g_mutex,NULL); 110 111 //创建若干个线程,执行消费任务。 112 for(i=0;i<CONSUMERS_COUNT;i++) 113 { 114 pthread_create(&g_thread[i],NULL,consume,(void*)i);//产生了段错误.我们传递的是值,所以int num=(int)arg 而不是int num=*(int*)arg 115 } 116 //创建若干个线程,执行生产任务。 117 for(i=0;i<PRODUCERS_COUNT;i++) 118 { 119 pthread_create(&g_thread[i+CONSUMERS_COUNT],NULL,produce,(void*)i); 120 } 121 //主线程等待这些线程结束 122 for(i=0;i<CONSUMERS_COUNT+PRODUCERS_COUNT;i++) 123 { 124 pthread_join(g_thread[i],NULL); 125 } 126 127 sem_destroy(&g_sem_full);//销毁POSIX信号量 128 sem_destroy(&g_sem_empty); 129 pthread_mutex_destroy(&g_mutex); 130 return 0; 131 }
  • 相关阅读:
    mysql主从复制读写分离的配置方法详解
    JS如何给ul下的所有li绑定点击事件,点击使其弹出下标和内容
    C#中的参数和调用方式(可选参数、具名参数、可空参数)
    关于HTML5的data-*自定义属性的总结
    在Java代码中解析html,获取其中的值方法
    Java面向对象之成员隐藏与属性封装操作示例
    《设计原本》读书笔记03
    java双重检查锁定的实现代码
    微信公众号开发之设置自定义菜单实例代码【java版】
    深入学习Redis(3):主从复制
  • 原文地址:https://www.cnblogs.com/wsw-seu/p/8502688.html
Copyright © 2020-2023  润新知