linux c++(线程 & 信号量 & 生产者消费者模型)

生产者和消费者模型

信号量[加强版的互斥锁]

  • int sem_init(setm_t *sem,int pshared,unsigned int valud);
    • sem 定义的信号量,传出
    • pshared
      • 0 代表线程信号量
      • 非0 代表进程信号量
    • value 定义信号量的个数
  • 摧毁信号量
    • int sem_destory(sem_t *sem);
  • 申请信号量,申请成功 value--
    - int sem_wait(sem_t *sem);
    • 信号量为0时,阻塞
  • 释放信号量value++
    • int sem_post(sem_t *sem);

  #include <semaphore.h>                                                            
  sem_t blank,xfull;
  #define  __SEM_CNT__ 5
  
  int queue[__SEM_CNT__];
  int beginnum = 100;
  
✹ void * thr_producter(void *arg)
  {   
      int i = 0;
      while(1)
      {   
          sem_wait(&blank);//申请资源 blank--
          printf("----%s----self---%lu----%d\n",__FUNCTION__,pthread_self(),beginnum
          queue[(i++)%__SEM_CNT__] = beginnum++;
          sem_post(&xfull);//xfull ++
          sleep(rand()%3);
      }
      pthread_exit(NULL);
  }
  // 创建线程 #include <pthread.h>
✹ void * thr_custmer(void *arg)
  {   
      int i = 0,num = 0;
      while(1)
      {   
          sem_wait(&xfull);
          num = queue[(i++)%__SEM_CNT__];
          printf("----%s----self---%lu----%d\n",__FUNCTION__,pthread_self(),num);
          sem_post(&blank);
          sleep(rand()%3);
      }
      pthread_exit(NULL);
  }
   int main()
  {
      sem_init(&blank,0,__SEM_CNT__);
      sem_init(&xfull,0,0);
      
      pthread_attr_t attr;
      pthread_attr_init(&attr);
      pthread_attr_setdetachstate(&attr,PTHREAD_CREATE_DETACHED);
      pthread_t tid[2];
      pthread_create(&tid[0],&attr,thr_producter,NULL);
      pthread_create(&tid[1],&attr,thr_custmer,NULL);
      pthread_attr_destroy(&attr);
      pthread_exit(NULL);
  
      sem_destroy(&blank);
      sem_destroy(&xfull);
  
      return 0;
  }

信号量就是在一个叫做互斥区的门口放一个盒子,盒子里面装着固定数量的小球,每个线程过来的时候,都从盒子里面摸走一个小球,然后去互斥区里面浪(?),浪开心了出来的时候,再把小球放回盒子里。如果一个线程走过来一摸盒子,得,一个球都没了,不拿球不让进啊,那就只能站在门口等一个线程出来放回来一个球,再进去。这样由于小球的数量是固定的,那么互斥区里面的最大线程数量就是固定的,不会出现一下进去太多线程把互斥区给挤爆了的情况。这是用信号量做并发量限制。
另外一些情况下,小球是一次性的,线程拿走一个进了门,就把小球扔掉了,这样用着用着小球就没了,不过有另外一些线程(一般叫做生产者)会时不时过来往盒子里再放几个球,这样就可以有新的线程(一般叫做消费者)进去了,放一个球进一个线程,这是信号量做同步功能。你截图里的例子就是这个情况,主线程是生产者,通过sem_post往盒子里放小球(信号量加一),而其他线程是消费者,通过sem_wait从盒子里拿小球(信号量减一),如果遇到盒子里一个小球都没有(信号量为0),就会开始等待信号量不为0,然后拿走一个小球(信号量减一)再继续。
本质上来说信号量就是那个盒子,以及“摸不到球就不让进”这个机制。

顺便你这个例子其实有点问题,发送信号量也就是放小球的这个过程并不会阻塞,会继续执行下去,那么有可能在消费者线程取走work_area里面的数据之前,下一个fgets就把这个数据覆盖了,这是个很危险的竞争冒险的问题,非常不符合多线程程序的设计准则。由于是从stdin当中读取数据,一般来说键盘是没有这么快,但要知道完全可以把输入重定向到文件,这时候就很容易出问题了

posted on 2021-05-07 17:54  lodger47  阅读(438)  评论(0)    收藏  举报

导航