C++11 操作系统原理 生产者消费者实验

看见网上给的生产者消费者的例子是基于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;
}

下面在时间间隔模式下进行演示:

参数如下:

 

 

 

打印缓冲区得到:

 

停止运行:

 

 

自动模式下的演示略过,动态的不易演示。

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值