前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >线程(三)生产者消费者模型+POSIX信号量

线程(三)生产者消费者模型+POSIX信号量

作者头像
海盗船长
发布2020-08-27 17:33:52
8570
发布2020-08-27 17:33:52
举报
文章被收录于专栏:基础知识文章基础知识文章

生产者消费者模型

使用消费者模型的原因:

生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。

生产者消费者模型优点
  • 解耦
  • 支持并发
  • 支持忙闲不均
在这里插入图片描述
在这里插入图片描述
基于BlockingQueue的生产者消费者模型
BlockingQueue

在多线程编程中阻塞队列(Blocking Queue)是一种常用于实现生产者和消费者模型的数据结构。其与普通的队列区别在于,当队列为空时,从队列获取元素的操作将会被阻塞,直到队列中被放入了元素;当队列满时,往队列里存放元素的操作也会被阻塞,直到有元素被从队列中取出(以上的操作都是基于不同的线程来说的,线程在对阻塞队列进程操作时会被阻塞)

在这里插入图片描述
在这里插入图片描述

Linux环境下C++ queue模拟阻塞队列的生产消费模型

代码语言:javascript
复制
#include <iostream>
#include <queue>
#include <stdlib.h>
#include <pthread.h>
 
#define NUM 8
 
class BlockQueue{
    private:
        std::queue<int> q;
        int cap;
        pthread_mutex_t lock;
        pthread_cond_t full;
        pthread_cond_t empty;
 
    private:
        void LockQueue()
        {
            pthread_mutex_lock(&lock);
        }
        void UnLockQueue()
        {
            pthread_mutex_unlock(&lock);
        }
        void ProductWait()
        {
            pthread_cond_wait(&full, &lock);
        }
        void ConsumeWait()
        {
            pthread_cond_wait(&empty, &lock);
        }
        void NotifyProduct()
        {
            pthread_cond_signal(&full);
        }
        void NotifyConsume()
        {
            pthread_cond_signal(&empty);
        }
        bool IsEmpty()
        {
            return ( q.size() == 0 ? true : false );
        }
        bool IsFull()
        {
            return ( q.size() == cap ? true : false );
            }
 
    public:
        BlockQueue(int _cap = NUM):cap(_cap)
        {
            pthread_mutex_init(&lock, NULL);
            pthread_cond_init(&full, NULL);
            pthread_cond_init(&empty, NULL);
        }
        void PushData(const int &data)
        {
            LockQueue();
            while(IsFull()){
                NotifyConsume();
                std::cout << "queue full, notify consume data, product stop." << 
std::endl;
                ProductWait();
            }
            q.push(data);
            UnLockQueue();
        }
        void PopData(int &data)
        {
            LockQueue();
            while(IsEmpty()){
                NotifyProduct();
                std::cout << "queue empty, notify product data, consume stop." << 
std::endl;
                ConsumeWait();
            }
            data = q.front();
            q.pop();
            UnLockQueue();
        }
        ~BlockQueue()
        {
            pthread_mutex_destroy(&lock);
            pthread_cond_destroy(&full);
            pthread_cond_destroy(&empty);
        }
};
 
void *consumer(void *arg)
{
    BlockQueue *bqp = (BlockQueue*)arg;
    int data;
    for( ; ; ){
        bqp->PopData(data);
        std::cout << "Consume data done : " << data << std::endl;
    }
}
void *producter(void *arg)
{
    BlockQueue *bqp = (BlockQueue*)arg;
    srand((unsigned long)time(NULL));
    for( ; ; ){
        int data = rand() % 1024;
        bqp->PushData(data);
        std::cout << "Prodoct data done: " << data << std::endl;
    }
}
 
int main()
{
    BlockQueue bq;
    pthread_t c,p;
    pthread_create(&c, NULL, consumer, (void*)&bq);
    pthread_create(&p, NULL, producter, (void*)&bq);
 
    pthread_join(c, NULL);
    pthread_join(p, NULL);
    return 0;
}

POSIX信号量

POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步。
初始化信号量
代码语言:javascript
复制
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
    pshared:0表示线程间共享,非零表示进程间共享
    value:信号量初始值
销毁信号量
代码语言:javascript
复制
int sem_destroy(sem_t *sem);
等待信号量
代码语言:javascript
复制
功能:等待信号量,会将信号量的值减1
int sem_wait(sem_t *sem);
发布信号量
代码语言:javascript
复制
功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1。
int sem_post(sem_t *sem);

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

  • 环形队列采用数组模拟,用模运算来模拟环状特性
在这里插入图片描述
在这里插入图片描述
  • 环形结构起始状态和结束状态都是一样的,不好判断为空或者为满,所以可以通过加计数器或者标记位来判断满或者空。另外也可以预留一个空的位置,作为满的状态
在这里插入图片描述
在这里插入图片描述

Linux环境下POSIX信号量环状队列的生产消费模型

代码语言:javascript
复制
#include <iostream>
#include <vector>
#include <stdlib.h>
#include <semaphore.h>
#include <pthread.h>
 
#define NUM 16
 
class RingQueue{
    private:
        std::vector<int> q;
        int cap;
        sem_t data_sem;
        sem_t space_sem;
        int consume_step;
        int product_step;
 
    public:
        RingQueue(int _cap = NUM):q(_cap),cap(_cap)
        {
            sem_init(&data_sem, 0, 0);
            sem_init(&space_sem, 0, cap);
            consume_step = 0;
            product_step = 0;
        }
        void PutData(const int &data)
        {
            sem_wait(&space_sem); // P
            q[consume_step] = data;
            consume_step++;
            consume_step %= cap;
            sem_post(&data_sem); //V
        }
        void GetData(int &data)
        {
            sem_wait(&data_sem);
            data = q[product_step];
            product_step++;
            product_step %= cap;
            sem_post(&space_sem);
        }
        ~RingQueue()
        {
            sem_destroy(&data_sem);
            sem_destroy(&space_sem);
        }
};
void *consumer(void *arg)
{
    RingQueue *rqp = (RingQueue*)arg;
    int data;
    for( ; ; ){
        rqp->GetData(data);
        std::cout << "Consume data done : " << data << std::endl;
        sleep(1);
    }
}
 
//more faster
void *producter(void *arg)
{
    RingQueue *rqp = (RingQueue*)arg;
    srand((unsigned long)time(NULL));
    for( ; ; ){
        int data = rand() % 1024;
        rqp->PutData(data);
        std::cout << "Prodoct data done: " << data << std::endl;
    //  sleep(1);
    }
}
 
int main()
{
    RingQueue rq;
    pthread_t c,p;
    pthread_create(&c, NULL, consumer, (void*)&rq);
    pthread_create(&p, NULL, producter, (void*)&rq);
 
    pthread_join(c, NULL);
    pthread_join(p, NULL);
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/03/16 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 生产者消费者模型
    • 使用消费者模型的原因:
      • 生产者消费者模型优点
        • 基于BlockingQueue的生产者消费者模型
          • Linux环境下C++ queue模拟阻塞队列的生产消费模型
          • POSIX信号量
            • 基于环形队列的生产消费模型
              • Linux环境下POSIX信号量环状队列的生产消费模型
              相关产品与服务
              容器服务
              腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档