Linu信号量

初始化信号量

cpp 复制代码
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
pshared:0表⽰线程间共享,⾮零表⽰进程间共享
value:信号量初始值

摧毁信号量

cpp 复制代码
int sem_destroy(sem_t *sem); 

等待信号量

cpp 复制代码
功能:等待信号量,会将信号量的值减1
int sem_wait(sem_t *sem); //P()

发布信号量

cpp 复制代码
功能:发布信号量,表⽰资源使⽤完毕,可以归还资源了。将信号量值加1。
int sem_post(sem_t *sem); //V()

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

复习环形队列

初始的时候环形队列的head和tail指向的都是同一个位置,在上图中也就是下标为0的位置,当环形队列为满的时候指向head和tail指向的也是0,因此根据head == tail == 0无法判端队列是空还是满的,因此要一个计数器来统计其中的元素个数

对信号量进行封装

cpp 复制代码
#pragma once
#include <iostream>
#include <semaphore.h>

namespace SemModlue
{
    int DefaultSemNum = 1;
    class Sem
    {
    public:
        Sem(int sem_value = DefaultSemNum)
            :_sem_value(sem_value)
        {
            sem_init(&_sem,0,_sem_value);
        }

        ~Sem()
        {
            sem_destroy(&_sem);
        }

        void P()
        {
            int n = sem_wait(&_sem);
            (void)n;
        }

        void V()
        {
            int n = sem_post(&_sem);
            (void)n;
        }
    private:
        sem_t _sem;             //信号量
        int _sem_value;         //信号量个数
    };
}

对环形队列进行封装

cpp 复制代码
#pragma once
#include <iostream>
#include <vector>
#include <pthread.h>
#include <semaphore.h>
#include "Sem.hpp"

namespace RingBufferModule
{
    using namespace SemModlue; 
    template <typename T>
    class RingBuffer
    {
    public:
        RingBuffer(int cap)
            :_ring(cap)
            ,_cap(cap)
            ,_p_step(0)
            ,_c_step(0)
            ,_space_num(cap)
            ,_data_num(0)
        {
            pthread_mutex_init(&_p_mutex,nullptr);
            pthread_mutex_init(&_c_mutex,nullptr);
        }

        ~RingBuffer()
        {
            pthread_mutex_destroy(&_p_mutex);
            pthread_mutex_destroy(&_c_mutex);
        }

        void Enqueue(const T&in)
        {
            _space_num.P();
            pthread_mutex_lock(&_p_mutex);
            _ring[_p_step] = in;
            _p_step++;
            _p_step %= _cap;
            pthread_mutex_unlock(&_p_mutex);
            _data_num.V();
        }

        void PopQueue(T *out)
        {
             _data_num.P();
            pthread_mutex_lock(&_c_mutex);
            *out = _ring[_c_step];
            _c_step++;
            _c_step %= _cap;
            pthread_mutex_unlock(&_c_mutex);
            _space_num.V();
        }
    private:
        std::vector<T> _ring;      //用vector来模拟环形队列
        int _cap;                  //容量
        int _p_step;               //生产者当前位置
        int _c_step;               //消费者当前位置
        pthread_mutex_t _p_mutex;  //生产者互斥锁
        pthread_mutex_t _c_mutex;  //消费者互斥锁
        Sem _space_num;            //当前空闲位置数量
        Sem _data_num;             //当前数据个数
    };
}

测试文件

cpp 复制代码
#include <iostream>
#include <unistd.h>
#include "Thread.hpp"
#include "BlockQueue.hpp"
#include "RingBuffer.hpp"

using namespace RingBufferModule;

void *Productor(void *args)
{
    RingBuffer<int> *ringbuffer = static_cast<RingBuffer<int> *>(args);
    int data = 0;
    while(true)
    { 
        //sleep(1);
        ringbuffer->Enqueue(data);
        std::cout << "生产了一个数据:" << data << std::endl;
        data++;
    }
}

void *Consumer(void *args)
{
    RingBuffer<int> *ringbuffer = static_cast<RingBuffer<int> *>(args);
    int data = 0;
    while(true)
    {
        sleep(1);
        ringbuffer->PopQueue(&data);
        std::cout << "消费了一个数据:" << data << std::endl;
    }
}

int main()
{
    RingBuffer<int> *ringbuffer=new RingBuffer<int>(5);
    pthread_t p1,p2,v1,v2,v3;
    pthread_create(&p1,nullptr,Productor,(void*)ringbuffer);
    pthread_create(&p2,nullptr,Productor,(void*)ringbuffer);
    pthread_create(&v1,nullptr,Consumer,(void*)ringbuffer);
    pthread_create(&v2,nullptr,Consumer,(void*)ringbuffer);
    pthread_create(&v3,nullptr,Consumer,(void*)ringbuffer);

    pthread_join(p1,nullptr);
    pthread_join(p2,nullptr);
    pthread_join(v1,nullptr);
    pthread_join(v2,nullptr);
    pthread_join(v3,nullptr);
    return 0;
}

运行结果