(1)什么是信号量
前面的叙述中,我们通过锁保证了每次只有一个线程进入临界区,但是临界区资源很多也很大,每次只允许一个线程进入往往会使效率很低。所以如果将临界区划分为多个独立的区域,划分为多少个区域就让多少个线程进入,,但是这样就同时带来了一个问题——如果划分为了5个区域,但是同时进入了10个线程该怎么办?所以这一点可以通过信号量解决。信号量可以理解为一个计数器,它用来描述临界资源的有效个数

信号量由一个值和一个指针组成,指针指向等待该信号量的线程。信号量的值表示相应资源的使用情况,比如如果S>=0表示资源够用,如果执行P操作表示请求分配一个资源,那么S就会减一;当S<0时表示已经没有可用资源(此时S的绝对值表示等待该资源的线程数)请求者必须等待其他线程释放资源方可继续运行。如果执行一个V操作就表示会释放一个资源,所以S加一

(2)与信号量相关的操作
1:要使用信号量就需要创建一个sem_t类型变量

#include <semaphore.h>//头文件
sem_t sem1;

2:在使用信号量前,需要对这个变量进行初始化,使用的函数是sem_init

int sem_init(sem_t* sem,int pshared,unsigned int value);
//pshared一般给0,非零表示进程间共享
//value:信号量初始值

3:信号量使用完毕需要用sem_destory进行销毁

int sem_destory(sem_t* sem);

4:POSIX信号量中的P操作对应的接口是sem_waitm,V操作对应的接口是sem_post

int sem_wait(sem_t* sem);
int sem_post(sem_t* sem);

(3)基于环形队列的生产者与消费者模型-信号量(单消费者单生产者)
基于阻塞队列的生产者与消费者模型存在一个很大的问题就是他们其实是在串行运行的,并没有并行运行,这就导致他们的效率不是很高,而使用环形队列则可以解决这个问题。
在这里,我们使用的载体是环形队列,他和数据结构的循环队列基本一致,在这里就不做过多介绍了,具体请移步
如下在这样的模型中,消费者和生产者都有各自的P,V操作,消费者关心的是队列中有没有数据,所以它进行P操作时申请的是数据,而进行V操作时归还的是空格资源;生产者关系的是队列中有没有空格,所以它进行P操作时申请的是空格,而进行V操作时由于生产好了数据归还的就是数据


这样的模型为什么可以实现并行操作呢?举例来说,当消费者和生产者启动时,由于队列中全部为空,所以即便消费者先运行它也会因为没有数据而被挂起,所以生产者就会先运行生产数据。一旦产生了数据,数据的信号量增加,于是消费者拿掉信号进行消费,一旦所有空格都存放了数据,那么生产者就会挂起,当消费者消费完一个数据,然后归还空格,于是生产者又会拿到信号启动生产。这样,只要队列中同时有空格和数据,生产者和消费者就能同时运行

如下,我们使用POSIX信号量。利用唤醒队列重写这个消费者生产者模型。
circular_queue.hpp如下

#include <iostream>
#include <vector>
#include <pthread.h>
#include <semaphore.h>
using namespace std;class CircularQueue
{private:vector<int> v;//用作循环队列int _cap;//队列大小sem_t data;//消费者信号量(消费者关注数据数量)sem_t blank;//生产者信号量(生产者关注空格数量)int com_index;//消费者的索引int pro_index;//生产者的索引public:CircularQueue(int cap=10):_cap(cap){v.resize(_cap);sem_init(&data,0,0);//初始化消费者信号量sem_init(&blank,0,_cap);///初始化生产者信号量com_index=0;pro_index=0;//索引开始时都指向0}~CircularQueue(){sem_destroy(&data);//销毁信号量sem_destroy(&blank);}void Put(const int& val)//生产者存放数据{   sem_wait(&blank);//P操作,生产者申请的是空格资源v[pro_index]=val;pro_index++;pro_index%=_cap;//环形队列sem_post(&data);//V操作,生产者释放的数据}void Get(int& val)//消费者取数据{sem_wait(&data);//P操作,消费者申请的是数据val=v[com_index];com_index++;com_index%=_cap;//环形sem_post(&blank);//V操作,消费者释放的是空格}
};

test.cpp如下

#include "circular_queue.hpp"
#include <unistd.h>CircularQueue* bq=new CircularQueue(10);void* consumer_run(void* arg)
{while(1){int data;bq->Get(data);printf("%s拿到数据:%d\n",(char*)arg,data);}
}void* productor_run(void* arg)
{int cout=1;while(1){if(cout==11)cout=1;bq->Put(cout);printf("%s放进数据:%d\n",(char*)arg,cout);cout++;sleep(1);}
}int main()
{pthread_t con,pro;pthread_create(&con,nullptr,consumer_run,(void*)"消费者");pthread_create(&pro,nullptr,productor_run,(void*)"生产者");pthread_join(con,nullptr);pthread_join(pro,nullptr);delete bq;return 0;}

效果如下,在这里限制生产者的速度,所以每当生产者生产一个的时候消费者才能消费。更多的时候,消费者生产者是并行的
(生产者慢,消费者快)

Linux系统编程 -- 多线程之基于环形队列的生产者与消费者模型相关推荐

  1. Linux系统编程40:多线程之基于环形队列的生产者与消费者模型

    文章目录 (1)什么是信号量 (2)与信号量相关的操作 (3)基于环形队列的生产者与消费者模型-信号量(单消费者单生产者) (1)什么是信号量 前面的叙述中,我们通过锁保证了每次只有一个线程进入临界区 ...

  2. Linux学习之系统编程篇:使用条件变量实现“生产者和消费者模型”

    #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <string.h&g ...

  3. [Linux]生产者消费者模型(基于BlockQueue的生产者消费者模型 | 基于环形队列的生产者消费者模型 | 信号量 )

    文章目录 生产者消费者模型 函数调用角度理解生产者消费者模型 生活角度理解生产者消费者模型 为什么要使用生产者消费者模型 生产者消费者模型优点 321原则 基于BlockingQueue的生产者消费者 ...

  4. Linux系统编程(七)消息队列

    Linux系统编程(七)消息队列 一.什么是消息队列 二.消息队列内部原理 三.实现消息队列的收发 1.发送消息队列 2.接收消息队列 四.消息队列与命名管道的比较 一.什么是消息队列 消息队列提供了 ...

  5. Linux环境编程多线程定时器、延时队列以及分布式定时器的现实与原理分析

    Linux环境编程多线程定时器.延时队列以及分布式定时器的现实与原理分析丨线程池丨中间件丨后端开发丨C/C++linux服务器开发 视频讲解如下,点击观看: Linux环境编程多线程定时器.延时队列以 ...

  6. 嵌入式Linux系统编程学习之八基于文件指针的文件操作

    文章目录 前言 一.文件的创建.打开与关闭 二.读写文件 三.文件定位 四.标准输入/输出流 五.目录操作 前言   对文件进行操作有打开文件.关闭文件.读写文件.   文件指针:每打开一个文件,就返 ...

  7. linux编程基础_第1篇 Linux系统编程 -多线程基础

    进程 在理解线程之前,首先需要了解UNIX/Linux进程. 进程是由操作系统创建的,需要相当数量的"开销". 进程包含有关程序资源和程序执行状态的信息,包括:它是一个在随机访问内 ...

  8. 【Linux系统编程】进程间通信之消息队列

    00. 目录 文章目录 00. 目录 01. 消息队列概述 02. 消息队列相关函数 03. 消息队列读写操作 04. 测试代码 05. 附录 01. 消息队列概述 消息队列提供了一种在两个不相关的进 ...

  9. 【README】Linux系统编程必读:本专栏内容提要以及系统调用接口总结

    文章目录 前言 第一部分:博客知识点 (1)基础篇 Linux系统编程1:Linux中使用率最高的一些命令 Linux系统编程2:详解Linux中的权限问题 Linux系统编程3:基础篇之详解Linu ...

  10. 【Linux下】 线程同步 生产者与消费者模型

    文章目录 [Linux下] 线程同步 生产者与消费者模型 线程同步 同步概念与竞态条件 条件变量 条件变量本质 操作条件变量 初始化和销毁条件变量 等待 唤醒 通过条件变量实现的简单线程同步例子 为什 ...

最新文章

  1. shell常用的基础命令
  2. linux我安装虚拟机后安装FTP出现如下错误求解决
  3. 百信银行基于 Apache Hudi 实时数据湖演进方案
  4. CH - 6803 导弹防御塔(二分图最大匹配-多重匹配(拆点法))
  5. PWN-COMPETITION-HGAME2022-Week4
  6. linux的驱动开发——字符设备驱动
  7. wuauclt.exe是什么进程?
  8. postifx网络服务的搭建和配置
  9. 高项计算题2-三点估算(计划评审技术PERT),时差,投资回收期,贴现率,沟通渠道
  10. CSS改变table内置tbody滚动条
  11. 面板数据熵值法计算综合指数Stata代码(附样本数据和结果)
  12. 基于单片机的RFID刷卡门禁电路设计(#0206)
  13. Excel技巧分享:合并单元格如何分组排序
  14. 渗透学习-SQL注入篇-基础知识的学习(持续更新中)
  15. 历史题材类自媒体如何抓住用户的痛点
  16. Android 程序常用功能《清除缓存》
  17. 戴姆勒与Infosys结成战略合作伙伴关系,推动创新及IT基础设施转型
  18. Warmup Learning
  19. yeah邮箱功能测试
  20. C语言调用so动态库的两种方式

热门文章

  1. bzoj3531: [Sdoi2014]旅行 (树链剖分 动态开点线段树)
  2. VS 添加代理 -NUGET
  3. “我爱淘”冲刺阶段Scrum站立会议3
  4. R 保存包含中文的 eps 图片--showtext
  5. Java jdk下载及安装
  6. 游戏开发之C++对C的扩展(C++基础)
  7. MySQL读写分离详解(二)——MyCAT实战配置
  8. 计算机网络误区——源目IP和源目MAC变化问题
  9. 使用NFS搭建WEB服务器集群
  10. iOS开发点滴 - 关闭键盘