看见网上给的生产者消费者的例子是基于windows API下的编程,不但脱离了操作系统底层设计的初衷,还更依赖于平台。
故使用C++13标准,重写了生产者消费者模拟程序。
首先,由于C++没有信号量机制,利用互斥锁实现一个信号量类。代码如下:
【Semaphore.h】
/*
一个信号量类(来自网络)
*/
#pragma once
#include<mutex>
class Semaphore
{
public:
Semaphore(unsigned long count = 0) : m_count(count) {}
Semaphore(const Semaphore&) = delete;
Semaphore& operator=(const Semaphore&) = delete;
void Signal(){
{
std::unique_lock<std::mutex> lock(m_mutex);
++m_count;
}
m_cv_uptr.notify_one();
}
void Wait(){
std::unique_lock<std::mutex> lock(m_mutex);
while (m_count == 0) { // 这里可能会虚假唤醒
m_cv_uptr.wait(lock);
}
--m_count;
}
private:
std::mutex m_mutex;
std::condition_variable m_cv_uptr;
unsigned long m_count;
};
其次,定义一个BufferSimulation类,来实现缓冲区的模拟
【BufferSimulation.h】
/*
使用C++11标准
写了一个消费者生产者——缓冲区类
作者:吕翔宇
E-mail:630056108@qq.com
2019年5月26日
版权所有 ALL RIGHTS RESERVED!
*/
#pragma warning(disable:4996)
#pragma once
#include<iostream>
#include<vector>
#include<string>
#include<mutex>
#include<thread>
#include"Semaphore.h"
class BufferSimulation{
public:
BufferSimulation(int producerNum, int consumerNum, int bufferSize, int delayTime, bool stepMode);
~BufferSimulation();
private:
std::vector<std::string> buffer; // 缓冲区
std::vector<std::thread> producers; // 生产者们
std::vector<std::thread> consumers; // 消费者们
int producerNum, consumerNum, bufferSize, delayTime;
std::mutex t_mutex; // 用于线程间的互斥
Semaphore bufferSemaphore; // 缓冲区信号量
int produce_ptr; // 生产者放置位置
int consume_ptr; // 消费者使用位置
bool stop;
int count = 0; // 记录当前货物编号
std::thread stepModeThread; // 步过进程
public:
void printBuffer(int loc);
private:
void produce(int id); // 生产程序
void consume(int id); // 消费程序
void stepMode(); // 单步模式
public:
bool canStop;
};
其实现代码如下
【BufferSimulation.cpp】
/*
使用C++11标准
写了一个消费者生产者——缓冲区类
作者:吕翔宇
E-mail:630056108@qq.com
2019年5月26日
版权所有 ALL RIGHTS RESERVED!
*/
#include "BufferSimulation.h"
BufferSimulation::BufferSimulation(int producerNum, int consumerNum, int bufferSize, int delayTime, bool stepMode) :
producerNum(producerNum),
consumerNum(consumerNum),
bufferSize(bufferSize),
delayTime(delayTime),
stop(false),
bufferSemaphore(bufferSize), // 信号量与缓冲区大小一致
buffer(bufferSize),
canStop(false)
{
if (stepMode)
stepModeThread = std::thread(&BufferSimulation::stepMode, this);
else
canStop = true;
for (int i = 0; i < producerNum; i++) {
producers.push_back(std::thread(&BufferSimulation::produce, this,i));
std::cout << "创建了一个生产者者进程!" <<"进程号为:"<< producers[i].get_id()<< std::endl;
}
// 创建消费者
for (int j = 0; j < consumerNum; j++) {
consumers.push_back(std::thread(&BufferSimulation::consume, this,j));
std::cout << "创建了一个消费者进程!" << "进程号为:" << consumers[j].get_id() << std::endl;
}
}
void BufferSimulation::stepMode() {
canStop = false;
bool pass = true;
while (true) {
_sleep(300);
if (pass) {
t_mutex.lock();
pass = false;
}
std::cout << "\n指令 1.停止运行 2.调到下一秒 3.打印缓冲区\n请输入:";
int tmp;
std::cin >> tmp;
if (tmp == 1) {
stop = true;
t_mutex.unlock();
_sleep(delayTime);
canStop = true;
return;
}else {
if (tmp == 2) {
t_mutex.unlock();
_sleep(1000);
pass = true;
}
else {
if (tmp == 3) {
printBuffer(-1);
}
else {
std::cout << "指令无效\n";
}
}
}
}
}
BufferSimulation::~BufferSimulation()
{
stop = true;
for (int i = 0; i < producerNum; i++) {
producers[i].detach();
}
for (int i = 0; i < consumerNum; i++) {
std::cout << "销毁消费者" << std::endl;
consumers[i].detach();
}
system("pause");
}
void BufferSimulation::printBuffer(int loc) {
std::cout << "————————————" << std::endl;
std::cout << "缓冲区号\t\t内容\n";
for (int i = 0; i < bufferSize; i++) {
if (i != loc) {
std::cout << i << "\t\t\t" << buffer[i] << "\n";
}
else {
std::cout << i << "\t\t\t" << buffer[i] << "\t<--"<<"\n";
}
}
std::cout << "————————————" << std::endl;
}
void BufferSimulation::produce(int id) {
while (true) {
if (stop) {
std::cout << "\n生产者 " << id << " 退出\n";
break;
}
_sleep(delayTime);
bufferSemaphore.Wait(); // 等待有地方放
t_mutex.lock();
if (stop) {
bufferSemaphore.Signal();
t_mutex.unlock();
std::cout << "\n生产者 " << id << " 退出\n";
break;
}
buffer[produce_ptr] = std::to_string(count);
printBuffer(produce_ptr);
produce_ptr = (produce_ptr + 1) % bufferSize;
std::cout << std::this_thread::get_id()<<" "<< id << "号进程(生产者)生产:" << count << std::endl;
count++;
t_mutex.unlock();
}
}
void BufferSimulation::consume(int id) {
while (true) {
if (stop) {
std::cout << "\n消费者 " << id << " 退出\n";
break;
}
_sleep(delayTime);
bufferSemaphore.Signal(); // 等待有东西用
t_mutex.lock();
if (stop) {
bufferSemaphore.Wait();
t_mutex.unlock();
std::cout << "\n消费者 " << id << " 退出\n";
break;
}
std::string product = buffer[consume_ptr];
buffer[consume_ptr] = "";
printBuffer(consume_ptr);
consume_ptr = (consume_ptr + 1) % bufferSize;
std::cout << std::this_thread::get_id() << " " << id << "号进程(消费者)消费:" << product << std::endl;
t_mutex.unlock();
}
}
【main.cpp】
/*
基于C++11模拟生产者-消费者,缓冲队列的实现
作者:吕翔宇
E-Mail:630056108@qq.com
2019年5月26日
版权所有 ALL RIGHTS RESERVED!
*/
#include"BufferSimulation.h"
int main(int argc, char ** argv) {
int producerNum; int consumerNum; int bufferSize; int delayTime; bool stepMode;
std::cout << "生产者数:";
std::cin >> producerNum;
std::cout << "消费者数:";
std::cin >> consumerNum;
std::cout << "缓冲区大小:";
std::cin >> bufferSize;
std::cout << "间隔大小(毫秒):";
std::cin >> delayTime;
std::cout << "是否步过模式(0:自动运行,1:步过模式):";
std::cin >> stepMode;
BufferSimulation simulation(producerNum, consumerNum, bufferSize, delayTime, stepMode);
while (!simulation.canStop) _sleep(1000);
system("pause");
return 0;
}
下面在时间间隔模式下进行演示:
参数如下:
打印缓冲区得到:
停止运行:
自动模式下的演示略过,动态的不易演示。