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:[email protected]
	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:[email protected]
	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:[email protected]
	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;
}

下面在時間間隔模式下進行演示:

參數如下:

 

 

 

打印緩衝區得到:

 

停止運行:

 

 

自動模式下的演示略過,動態的不易演示。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章