wordpress图片转文字,免费优化关键词,快云助手网站建设视频教程,电子商务网站建设汉狮Linux 操作系统#xff1a;基于环形队列的生产者消费者模型 一、前言二、大致框架二、P操作、V操作三、生产者生产数据四、生产者获取数据五、代码测试六、所有代码 一、前言 环形队列采用数组模拟#xff0c;用模运算来模拟环状特性。和基于阻塞队列的生产者消费者模型不同的… Linux 操作系统基于环形队列的生产者消费者模型 一、前言二、大致框架二、P操作、V操作三、生产者生产数据四、生产者获取数据五、代码测试六、所有代码 一、前言 环形队列采用数组模拟用模运算来模拟环状特性。和基于阻塞队列的生产者消费者模型不同的是环形队列将公共资源分成多份使用而阻塞队列则是将公共资源当作一个整体使用
Linux OS线程封装 | RAII封装锁 | 随机数运算任务封装
二、大致框架 毫无疑问我们首先需要一个数组来模拟环形队列并且环形队列的大小也需指明由于我们是将公共资源即环形队列分为多个小块单独使用生产者向环形队列中插入数据生产者向环形队列中取数据。这也意味着生产者和消费者的步数不一致我们需要两个变量分别记录生产者和消费者的运动下标。 对于生产者来说空间是资源对于消费者来所数据是资源。并且生产者不能把消费者套一个圈此时队列已经为满消费者不能超越生产者此时队列已经为空。由于环形结构起始状态和结束状态都是一样的不好判断为空或者为所以我们引入两把计数器分别表示公共资源的个数即信号量初始时生产者空间资源为整个数组消费者数据资源为0 生产者消费者模型是多生产者多消费者间的消费模型。这也意味者可能存在多个生产者或多个消费者并发访问公共资源会导致多执行流数据不一致问题所以我们要为生产者和消费者各自维护一把锁
【大致框架】
const int defaultSize 5; //环形队列大小默认值template class T
class RingQueue
{
public:RingQueue(int size defaultSize): _size(size), _ringqueue(size), _p_step(0), _c_step(0){sem_init(_data_sem, 0, 0);sem_init(_space_sem, 0, size);pthread_mutex_init(_mutex_p, nullptr);pthread_mutex_init(_mutex_c, nullptr);}~RingQueue(){sem_destroy(_data_sem);sem_destroy(_space_sem);pthread_mutex_destroy(_mutex_c);pthread_mutex_destroy(_mutex_p);}private:std::vectorT _ringqueue;int _size;int _p_step; // 生产者int _c_step; // 消费者sem_t _data_sem; // 消费者使用sem_t _space_sem; // 生产者使用pthread_mutex_t _mutex_p; // 生产者使用pthread_mutex_t _mutex_c; // 消费者使用
};二、P操作、V操作 由于后续生产者和消费者都需要进行P申请信号量、V(释放信号量)。所以我们在这对PV进行封装 【具体如下】 void P(sem_t sem) // 申请信号量{sem_wait(sem); // 等待信号量等待成功会将信号量的值减1}void V(sem_t sem) // 释放信号量{sem_post(sem); // 发布信号量表示资源使用完毕可以归还资源了。将信号量值加1}三、生产者生产数据 生产者要想环形队列中插入数据首先需要P操作申请空间资源。一旦申请成功就意味着完成了对空间资源的预定。换而言之环形队列还未满还可以继续插入数据。为了防止多生产并发访问环形队列记下来就是申请锁了。 只有两者都成功了生产者才能向环形队列中Push数据。插入成功后更新生产者步数下标即可
【具体代码】
void Push(T in)
{P(_space_sem);{// LockGuard具体代码查看前言链接LockGuard lock(_mutex_p);// RAII思想对锁进行了疯转代替注释的显示加锁和解锁操作// pthread_mutex_lock(_mutex_p);_ringqueue[_p_step] in;_p_step;_p_step % _size;// pthread_mutex_unlock(_mutex_p);}V(_data_sem);
}四、生产者获取数据 我们给Pop函数传递一个输出型参数将生产者需要的数据带出 和消费行为一样生产者首先需要生产空间资源即空间信号量、锁。然后将环形队列中的数据赋值个输出型产生然后更新步数下标即可
【具体代码】
void Pop(T *out)
{P(_data_sem);{// LockGuard具体代码查看前言链接LockGuard lock(_mutex_c);// RAII思想对锁进行了疯转代替注释的显示加锁和解锁操作// pthread_mutex_lock(_mutex_c);*out _ringqueue[_c_step];_c_step;_c_step % _size;// pthread_mutex_unlock(_mutex_c);}V(_space_sem);
}五、代码测试 这里我们创建3个生产者和2个消费者。生产者插入的数据为2个随机数和随机运算符构造的任务Task消费者直接获取任务执行消费者启动时先睡眠3秒让生产者将环形队列填充满后在消费 【具体代码】
void *Productor(void *args)
{RingQueueTask *rq static_castRingQueueTask *(args);while(true){// sleep(1);int data_x rand() % 10 1;usleep(1000);int data_y rand() % 10 1;usleep(1000);char op opers[rand() % opers.size()];Task t(data_x, data_y, op);rq-Push(t);std::cout Productor: t.PrintTask() std::endl;}
}void *Consumer(void *args)
{sleep(3);RingQueueTask *rq static_castRingQueueTask *(args);while(true){sleep(1);Task t;rq-Pop(t);t();std::cout Consumer: t.PrintResult() std::endl;}
}int main()
{srand(time(nullptr) ^ pthread_self() ^ getpid());RingQueueTask rq;pthread_t p[3], c[2];pthread_create(p[0], nullptr, Productor, rq);pthread_create(p[1], nullptr, Productor, rq);pthread_create(p[2], nullptr, Productor, rq);pthread_create(c[0], nullptr, Consumer, rq);pthread_create(c[1], nullptr, Consumer, rq);pthread_join(p[0], nullptr);pthread_join(p[1], nullptr);pthread_join(p[2], nullptr);pthread_join(c[0], nullptr);pthread_join(c[1], nullptr);return 0;
}【运行结果】
六、所有代码
gitee基于环形队列的生产者消费者模型