Linux:POSIX信号量 | 环形队列的生产消费模型


全文约 2409 字,预计阅读时长: 7分钟


POSIX信号量

  将临界资源分成多份,支持多线程并发同步。互斥锁能保护临界资源,条件变量能帮我们直到临界资源的状态。信号量是一种资源的预定机制。线程来了,获取信号量,有资源就进去执行,执行完毕,让出资源;获取信号量时没有资源,则挂起等待。信号量本身也是一种临界资源,所以其P(申请资源)V(释放资源操作)操作是原子性的。
在这里插入图片描述

  • 操作系统提供了一种信号量类型:sem_t
  • 初始化信号量:int sem_init(sem_t *sem, int pshared, unsigned int value);
    • 参数:pshared:0表示线程间共享,非零表示进程间共享。一般设置为0.
    • value:信号量初始值,多少份临界资源。
  • 销毁信号量:int sem_destroy(sem_t *sem);
  • 等待信号量:int sem_wait(sem_t *sem);
    • 会将信号量的值减1,等同于:sem--;大于0,立即返回;反之则阻塞等待。
  • 发布信号量:int sem_post(sem_t *sem);
    • 会将信号量的值加1,等同于:sem++

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

  • 环形队列采用数组模拟,用模运算来模拟环状特性
    在这里插入图片描述
  • 生产者优先执行;差一个为满;不空不满,消费者生产者同时执行。现在结合信号量这个计数器,就很简单的进行多线程间的同步过程。
  • 计算【1–N】之间的和:
---//hpp
#pragma once 

#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>

template <class T>
class RingQueue{
    private:
        int cap;
        std::vector<T> ring;
        //生产和消费必须有自己的位置下标
        int c_index;
        int p_index;

        pthread_mutex_t c_lock;//多个消费线程
        pthread_mutex_t p_lock;//多个生产线程 都要保证互斥

        sem_t sem_space;
        sem_t sem_data;
    public:
        RingQueue(int _cap):cap(_cap), ring(_cap), c_index(0), p_index(0)
        {
            pthread_mutex_init(&c_lock, nullptr);
            pthread_mutex_init(&p_lock, nullptr);

            sem_init(&sem_space, 0, _cap);
            sem_init(&sem_data, 0, 0);
        }
        void Put(const T &in)
        {
            sem_wait(&sem_space);
            //lock //生产者
            ring[p_index] = in;
            sem_post(&sem_data);

            p_index++;
            p_index %= cap;
            //unlock
        }
        void Get(T *out)
        {
            sem_wait(&sem_data);
            //lock 消费者
            *out = ring[c_index];
            sem_post(&sem_space);

            c_index++;
            c_index %= cap;
            //unlock
        }
        ~RingQueue()
        {
            pthread_mutex_destroy(&c_lock);
            pthread_mutex_destroy(&p_lock);

            sem_destroy(&sem_space);
            sem_destroy(&sem_data);
        }
};

---//main.cc
#include "RingQueue.hpp"
#include "Task.hpp"
#include <pthread.h>
#include <ctime>
#include <cstdlib>
#include <unistd.h>

void *consumer(void *ring_queue)
{
    RingQueue<Task> *rq = (RingQueue<Task>*)ring_queue;
    
    while(true){
        //sleep(1);
        //1. 消费任务
        Task t;
        rq->Get(&t); 
        
        //2. 处理任务
        int result = t.Handler();
        std::cout << "消费者: hander Task Done , result: " << result << std::endl;
    }
}

void *producter(void *ring_queue)
{
    RingQueue<Task> *rq = (RingQueue<Task>*)ring_queue;
    while(true){
        //1. 制造任务, 或者别人给你的
        int top = rand()%20000+1; //[1, 2000]
        Task t(top);
        t.Show();

        //2. 生产任务
        rq->Put(t);
    }
}

int main()
{
    RingQueue<Task> *rq = new RingQueue<Task>(10);

    pthread_t c, p;
    pthread_create(&c, nullptr, consumer, rq);
    pthread_create(&p, nullptr, producter, rq);

    pthread_join(c, nullptr);
    pthread_join(p, nullptr);
    return 0;
}

---//任务.hpp
#include <iostream>

class Task{
    private:
        int top; //[1,top]
    public:
        Task()
        	:top(1)
        {}
        Task(int _top)
        	:top(_top)
        {}
        int Handler()
        {
            int sum = 0;
            for(auto i= 0; i <= top; i++){
                sum += i;
            }
            return sum;
        }
        void Show()
        {
            std::cout << "生产者:这个任务是:累加数据从1~" << top << std::endl;
        }
        ~Task()
        {}
};

寄语

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值