【Linux】—— 基于信号量的生产者消费者模型

信号量

前面我们在基于阻塞队列的生产者消费者模型 今天我们来看一下基于信号量的生产者消费者模型,也可以说是基于环形队列的。

POSIX信号量

POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步

初始化信号量
#include <semaphore.h>
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
		pshared:0表示线程间共享,非零表示进程间共享
		value:信号量初始值
销毁信号量
int sem_destroy(sem_t *sem);
等待信号量
功能:等待信号量,会将信号量的值减1
int sem_wait(sem_t *sem);
发布信号量
功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1。
int sem_post(sem_t *sem);
基于环形队列的生产者消费者模型
  • 环形队列采用数组模拟,用模运算来模拟环状特性
  • 环形结构起始状态和结束状态都是一样的,不好判断为空或者为满,所以可以通过加计数器或者标记位来判断满或者空。另外也可以预留一个空的位置,作为满的状态
  • 但是我们现在有信号量这个计数器,就很简单的进行多线程间的同步过程
  • 简单的总结一句话就是,你不能超过我,我不能把你套个圈,这里你是消费者,我是生产者
源码展示
  • ring.hpp
#ifndef __RING_HPP__
#define __RING_HPP__

#include <iostream>
#include <semaphore.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>

#define NUM 32

using namespace std;

class Ring{
    private:
        int circle[NUM];//环形队列
        int cap;//信号量的容量
        int c_step;//消费者下标
        int p_step;//生产者下标
        sem_t sem_data;//消费者可以消费的数据
        sem_t sem_blank;//生产者可以生产的位置

        void P(sem_t &s)
        {
            sem_wait(&s);
        }
        void V(sem_t &s)
        {
            sem_post(&s);
        }
    public:
        Ring():cap(NUM)
        {
            c_step = p_step = 0;
            sem_init(&sem_data,0,0);
            sem_init(&sem_blank,0,NUM);
        }

        //消费者调用该接口进行消费
        void GetData(int& out)
        {
            P(sem_data);//消费者申请数据资源消费
            out = circle[c_step];//消费者从环形队列中取数据
            c_step++;
            V(sem_blank);//消费者增加空间
            c_step %= cap;//当走到最后时重新置为0
        }
        //生产者调用该接口进行生产
        void PutData(const int& in)
        {
            P(sem_blank);//生产者申请空间生产
            circle[p_step] = in;//往环形队列中插入数据
            p_step++;//下标++
            V(sem_data);//生产者增加数据
            p_step %= cap;//因为是环形队列,当走到下标最后时将它重置为0
        }

        ~Ring()
        {
            sem_destroy(&sem_data);
            sem_destroy(&sem_blank);
        }
};

#endif
#include "ring.hpp"
#include <time.h>

void* consumer(void* arg)
{
    Ring* r = (Ring*)arg;
    int data;
    for(;;){
        r->GetData(data);
        cout << "consumer data:"<< data <<endl;
    }
}

void* producter(void* arg)
{
    Ring* r = (Ring*)arg;
    for(;;){
        int data = rand() % 100 + 1;
        r->PutData(data);
        cout << "product data:"<< data <<endl;
        sleep(1);
    }
}

int main()
{
    srand((unsigned long)time(NULL));//生成随机数
    Ring r;//定义一个环形队列,基于信号量
    pthread_t c,p;//创建两个线程c为消费者,p为生产者
    pthread_create(&c,NULL,consumer,(void*)&r);//让生产者和消费者都看到该环形队列
    pthread_create(&p,NULL,producter,(void*)&r);


    pthread_join(c,NULL);
    pthread_join(p,NULL);

    return 0;
}
  • Makefile
ring:ring.cc
	g++ -o $@ $^ -lpthread
.PHONY:clean
clean:
	rm -f ring
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值