博客
关于我
Linux系统编程40:多线程之基于环形队列的生产者与消费者模型
阅读量:207 次
发布时间:2019-02-28

本文共 2833 字,大约阅读时间需要 9 分钟。

什么是信号量

在处理多线程程序时,临界区是需要保护的关键资源,但单独使用锁会导致效率低下。为了优化资源使用效率,信号量(Semaphore)提供了一种更灵活的资源管理机制。信号量可以看作是一个计数器,用于跟踪临界资源的可用数量。它通过两个操作——P(请求)和V(释放)来管理资源的分配和回收。

在传统的锁机制中,只能允许一个线程进入临界区,这限制了资源利用的潜力。信号量通过将临界区划分为多个独立的区域来解决这个问题。每个区域可以允许一个线程进入,从而提高整体的资源利用率。然而,如何处理超过指定区域数量的线程请求?这是信号量的核心作用。

信号量由两个部分组成:一个值(通常用S表示)和一个指针(用P指向等待该信号量的线程)。S的值反映了临界资源的状态:

  • 如果S ≥ 0,表示有相应数量的临界资源可用。
  • 如果执行P操作,请求分配一个资源,S会减一;如果S < 0,表示没有可用资源,此时S的绝对值表示等待该资源的线程数。请求者必须等待其他线程释放资源后才能继续运行。
  • 执行V操作时,释放一个资源,S会加一。

信号量的基本操作

在使用信号量之前,需要创建一个sem_t类型的变量。具体步骤如下:

  • 包含必要的头文件:
  • #include 
    1. 初始化信号量:使用sem_init函数初始化信号量。该函数的参数包括信号量变量、共享标志和初始值。
    2. int sem_init(sem_t* sem, int pshared, unsigned int value);
      • pshared一般设置为0,表示信号量仅在当前进程中使用。
      • value指定信号量的初始值。
      1. 销毁信号量:当信号量不再需要时,使用sem_destroy函数销毁它。
      2. int sem_destroy(sem_t* sem);
        1. 信号量操作接口:POSIX信号量定义了sem_wait和sem_post两个函数,分别对应P操作和V操作。
        2. int sem_wait(sem_t* sem);int sem_post(sem_t* sem);

          基于环形队列的生产者与消费者模型

          传统的阻塞队列模型中,生产者和消费者是串行运行的,这限制了它们的并行效率。环形队列(Circular Queue)通过并行化生产者和消费者来解决这一问题。每个生产者负责向队列中添加数据,每个消费者负责从队列中读取数据。

          在这种模型中,生产者和消费者都需要信号量来管理资源:

          • 消费者关心队列中是否有数据(P操作)。
          • 生产者关心队列中是否有空格(P操作)。

          通过信号量,生产者和消费者可以在不竞争的情况下并行运行。当队列为空时,消费者会被阻塞,直到生产者添加数据。当队列满时,生产者也会被阻塞,直到消费者释放空格。

          代码实现

          #include 
          #include
          #include
          #include
          using namespace std;class CircularQueue {private: vector
          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; } ~CircularQueue() { sem_destroy(&data); sem_destroy(&blank); } void Put(const int& val) { sem_wait(&blank); v[pro_index] = val; pro_index++; pro_index %= _cap; sem_post(&data); } void Get(int& val) { sem_wait(&data); val = v[com_index]; com_index++; com_index %= _cap; sem_post(&blank); }};

          测试程序

          #include "circular_queue.hpp"#include 
          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;}

          ###效果展示

          在本例中,生产者以较慢的速度工作(每秒生产一个数据),而消费者可以并行处理多个数据。这样可以避免生产者成为瓶颈,提升整体系统的效率。通过信号量的管理,生产者和消费者能够在不竞争的情况下高效运行。

    转载地址:http://visi.baihongyu.com/

    你可能感兴趣的文章
    python_引用的本质_栈内存和堆内存_内存示意图---python工作笔记017
    查看>>
    python_标识符_帮助系统的使用_命名规则---python工作笔记018
    查看>>
    python_海龟绘图_坐标系问题_画笔各种方法---python工作笔记013
    查看>>
    python_海龟绘图_画出奥运五环图---python工作笔记014
    查看>>
    Python_生产者消费者模型、管道、数据共享、进程池
    查看>>
    python_程序格式_缩进_行注释_段注释---python工作笔记012
    查看>>
    python_程序的构成---python工作笔记015
    查看>>
    python_超文本传输协议
    查看>>
    Python_集合
    查看>>
    Python|AsyncIO|TypeError:应为协程
    查看>>
    python——random模块的应用
    查看>>
    Python——基础知识细节
    查看>>
    Python——正则表达式
    查看>>
    Python—面向对象2
    查看>>
    Python“和“带整数的运算符
    查看>>
    Python“文件存在“制作目录时出错
    查看>>
    Python“文件存在“制作目录时出错
    查看>>
    Python、IMAP 和 GMail.将消息标记为已查看
    查看>>
    python一个一个获取迭代器的元素
    查看>>
    python一维数组 提取_python – 如何从numpy中的1维数组中提取零维切片
    查看>>