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); //P()

发布信号量

功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1。
 int sem_post(sem_t *sem);//V()

多线程程序中,使用信号量需遵守以下几条规则:

  1. 信号量的值不能小于 0;
  2. 有线程访问资源时,信号量执行“减 1”操作,访问完成后再执行“加 1”操作;
  3. 当信号量的值为 0 时,想访问资源的线程必须等待,直至信号量的值大于 0,等待的线程才能开始访问

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

环形队列采用数组模拟,用模运算来模拟环状特性

 

 

环形结构起始状态和结束状态都是一样的,不好判断为空或者为满,所以可以通过加计数器或者标记位来判断满或者空。另外也可以预留一个空的位置,作为满的状态

但是我们现在有信号量这个计数器,就很简单的进行多线程间的同步过程

 ring_queue.hpp

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

namespace Ns_Ring
{
    template <class T>
    class ring
    {
    public: 
        ring(size_t cap = 5)
            :_cap(cap)
            ,_v(cap)
        {
            _c_step = _p_step = 0;
            sem_init(&_is_empty,0,cap);
            sem_init(&_is_data,0,0);
        }
        void Pop(T*out)
        {
           sem_wait(&_is_data);
           *out = _v[_c_step];
           _c_step++;
           _c_step %= _cap;
           sem_post(&_is_empty);
        }
        void Push(const T & data)
        {
            sem_wait(&_is_empty);
            _v[_p_step] = data;
            ++_p_step;
            _p_step %= _cap;
            sem_post(&_is_data);
        }
        ~ring()
        {
            sem_destroy(&_is_empty);
            sem_destroy(&_is_data);
        }
    private:
        size_t _cap;
        std::vector<T> _v;
        sem_t _is_empty;
        sem_t _is_data;
        int _c_step;
        int _p_step;
    };
}

CpTest.cpp

#include "ring_queue.hpp"
#include<time.h>

void *consumer(void *args)
{
    Ns_Ring::ring<int>* r = (Ns_Ring::ring<int>*) args;
    while(true)
    {
        int data = 0;
        r->Pop(&data);
        std::cout<<"消费者消费:"<<data<<std::endl;
    }
}
void *producter(void *args)
{
    Ns_Ring::ring<int>* r = (Ns_Ring::ring<int>*) args;
    while(true)
    {
        int data = rand() % 20 + 1;
        r->Push(data);
        std::cout<<"生产者生产"<<data<<std::endl;
        sleep(1);
    }
}
int main()
{
    pthread_t c,p;
    Ns_Ring::ring<int>* r = new Ns_Ring::ring<int>();
    pthread_create(&c,nullptr,consumer,(Ns_Ring::ring<int>*)r);
    pthread_create(&p,nullptr,producter,(Ns_Ring::ring<int>*)r);

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

以上是单生产者消费者模型,如果需要实现多生产者多消费者需要加锁,代码如下:

 ring_queue.hpp

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

namespace Ns_Ring
{
    template <class T>
    class ring
    {
    public:
        ring(size_t cap = 5)
            : _cap(cap), _v(cap)
        {
            _c_step = _p_step = 0;
            sem_init(&_is_empty, 0, cap);
            sem_init(&_is_data, 0, 0);
            pthread_mutex_init(&_mutex, nullptr);
        }
        void Pop(T *out)
        {
            sem_wait(&_is_data);

            pthread_mutex_lock(&_mutex);
            *out = _v[_c_step];
            _c_step++;
            _c_step %= _cap;
            pthread_mutex_unlock(&_mutex);

            sem_post(&_is_empty);
        }
        void Push(const T &data)
        {
            sem_wait(&_is_empty);
            pthread_mutex_lock(&_mutex);

            _v[_p_step] = data;
            ++_p_step;
            _p_step %= _cap;
            pthread_mutex_unlock(&_mutex);
            sem_post(&_is_data);
        }
        ~ring()
        {
            sem_destroy(&_is_empty);
            sem_destroy(&_is_data);
            pthread_mutex_destroy(&_mutex);
        }

    private:
        size_t _cap;
        std::vector<T> _v;
        sem_t _is_empty;
        sem_t _is_data;
        int _c_step;
        int _p_step;
        pthread_mutex_t _mutex;
    };
}

CpTest.cpp

#include "ring_queue.hpp"
#include<time.h>

void *consumer(void *args)
{
    Ns_Ring::ring<int>* r = (Ns_Ring::ring<int>*) args;
    while(true)
    {
        int data = 0;
        r->Pop(&data);
        std::cout<<"消费者"<<pthread_self()<<"消费:"<<data<<std::endl;
    }
}
void *producter(void *args)
{
    Ns_Ring::ring<int>* r = (Ns_Ring::ring<int>*) args;
    while(true)
    {
        int data = rand() % 20 + 1;
        r->Push(data);
        std::cout<<"生产者"<<pthread_self()<<"生产"<<data<<std::endl;
        sleep(2);
    }
}
int main()
{
    pthread_t c,p;
    pthread_t c1,c2,c3,c4;
    pthread_t p1,p2,p3,p4;
    Ns_Ring::ring<int>* r = new Ns_Ring::ring<int>();
    pthread_create(&c,nullptr,consumer,(Ns_Ring::ring<int>*)r);
    pthread_create(&c1,nullptr,consumer,(Ns_Ring::ring<int>*)r);
    pthread_create(&c2,nullptr,consumer,(Ns_Ring::ring<int>*)r);
    pthread_create(&c3,nullptr,consumer,(Ns_Ring::ring<int>*)r);
    pthread_create(&c4,nullptr,consumer,(Ns_Ring::ring<int>*)r);

    pthread_create(&p,nullptr,producter,(Ns_Ring::ring<int>*)r);
    pthread_create(&p1,nullptr,producter,(Ns_Ring::ring<int>*)r);
    pthread_create(&p2,nullptr,producter,(Ns_Ring::ring<int>*)r);
    pthread_create(&p3,nullptr,producter,(Ns_Ring::ring<int>*)r);
    pthread_create(&p4,nullptr,producter,(Ns_Ring::ring<int>*)r);
    
    pthread_join(c,nullptr);
    pthread_join(p,nullptr);
}

下面我们实现在循环队列中加入任务代码如下:

ring_queue.hpp

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

namespace Ns_Ring
{
    template <class T>
    class ring
    {
    public:
        ring(size_t cap = 5)
            : _cap(cap), _v(cap)
        {
            _c_step = _p_step = 0;
            sem_init(&_is_empty, 0, cap);
            sem_init(&_is_data, 0, 0);
            pthread_mutex_init(&_mutex, nullptr);
        }
        void Pop(T *out)
        {
            sem_wait(&_is_data);

            pthread_mutex_lock(&_mutex);
            *out = _v[_c_step];
            _c_step++;
            _c_step %= _cap;
            pthread_mutex_unlock(&_mutex);

            sem_post(&_is_empty);
        }
        void Push(const T &data)
        {
            sem_wait(&_is_empty);
            pthread_mutex_lock(&_mutex);

            _v[_p_step] = data;
            ++_p_step;
            _p_step %= _cap;
            pthread_mutex_unlock(&_mutex);
            sem_post(&_is_data);
        }
        ~ring()
        {
            sem_destroy(&_is_empty);
            sem_destroy(&_is_data);
            pthread_mutex_destroy(&_mutex);
        }

    private:
        size_t _cap;
        std::vector<T> _v;
        sem_t _is_empty;
        sem_t _is_data;
        int _c_step;
        int _p_step;
        pthread_mutex_t _mutex;
    };
}

Task.hpp

#include <iostream>

namespace Ns_Task
{
    class task
    {
    public:
        task()
        {
        }
        task(const int &x, const int &y, const char op)
            : _x(x), _y(y), _op(op)
        {
        }
        int run()
        {
            int res = 0;
            switch (_op)
            {
            case '+':
                res = _x + _y;
                break;
            case '-':
            res = _x - _y;
                break;
            case '*':
            res = _x * _y;
                break;
            case '/':
            res = _x / _y;
                break;
            case '%':
            res = _x % _y;
                break;
            default:
                break;
            }
            return res;
        }
        ~task()
        {
        }

    private:
        int _x;
        int _y;
        char _op;
    };
}

CpTest.cpp

#include "ring_queue.hpp"
#include<time.h>
#include"Task.hpp"
void *consumer(void *args)
{
    Ns_Ring::ring<Ns_Task::task>* r =  (Ns_Ring::ring<Ns_Task::task>*) args;
    while(true)
    {
         Ns_Task::task t;
         r->Pop(&t);
         std::cout<<"消费数据是:"<<t.run()<<std::endl;
       /*
        int data = 0;
        r->Pop(&data);
        std::cout<<"消费者"<<pthread_self()<<"消费:"<<data<<std::endl;
        */
    }
}
void *producter(void *args)
{
    Ns_Ring::ring<Ns_Task::task>* r =  (Ns_Ring::ring<Ns_Task::task>*) args;
    while(true)
    {
        int x = rand()% 20 + 1;
        int y = rand()% 20 + 1;
        char op = "+-*/%"[rand() % 5];
        Ns_Task::task t(x,y,op);
        std::cout<<"生产数据是:"<<x<<op<<y<<std::endl;
        r->Push(t);
        sleep(2);
        /*
        int data = rand() % 20 + 1;
        r->Push(data);
        std::cout<<"生产者"<<pthread_self()<<"生产"<<data<<std::endl;
        sleep(2);
        */
    }
}
int main()
{
    pthread_t c,p;
    pthread_t c1,c2,c3,c4;
    pthread_t p1,p2,p3,p4;
   Ns_Ring::ring<Ns_Task::task>* r =  new Ns_Ring::ring<Ns_Task::task>;
    pthread_create(&c,nullptr,consumer,(Ns_Ring::ring<Ns_Task::task>*)r);
    pthread_create(&c1,nullptr,consumer,(Ns_Ring::ring<Ns_Task::task>*)r);
    pthread_create(&c2,nullptr,consumer,(Ns_Ring::ring<Ns_Task::task>*)r);
    pthread_create(&c3,nullptr,consumer,(Ns_Ring::ring<Ns_Task::task>*)r);
    pthread_create(&c4,nullptr,consumer,(Ns_Ring::ring<Ns_Task::task>*)r);

    pthread_create(&p,nullptr,producter,(Ns_Ring::ring<Ns_Task::task>*)r);
    pthread_create(&p1,nullptr,producter,(Ns_Ring::ring<Ns_Task::task>*)r);
    pthread_create(&p2,nullptr,producter,(Ns_Ring::ring<Ns_Task::task>*)r);
    pthread_create(&p3,nullptr,producter,(Ns_Ring::ring<Ns_Task::task>*)r);
    pthread_create(&p4,nullptr,producter,(Ns_Ring::ring<Ns_Task::task>*)r);
    
    pthread_join(c,nullptr);
    pthread_join(p,nullptr);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值