【操作系统实验】 c++11并发库实现[生产者消费者问题]和[读者写者问题]

应用Windows信号量机制实现进程(线程)的同步与互斥

  1. 掌握利用信号量机制实现进程同步互斥的工作原理;
  2. 学习Windows环境中的多线程并发执行机制。

第一部分:Windows提供的有关线程和信号量机制的函数和API

本篇主要用到了C++11的并发库std::thread、std::mutex、std::future、std::condition_variable、std::atomic。

std::thread

  1. 构造函数:
(1)default:
默认构造函数,创建一个空的thread执行对象。
thread() noexcept;

(2)initialization:
初始化构造函数,创建一个可以被joinable的thread执行对象。
template <class Fn, class... Args>
explicit thread (Fn&& fn, Args&&... args);

(3)copy[deleted]:
拷贝构造函数被禁用。
thread (const thread&) = delete;

(4)move:
move构造函数,调用成功后不代表任何thread执行对象。
thread (thread&& x) noexcept;

  1. move赋值操作:
(1)move:
赋值操作。如果当前对象不可joinable,需要传递右值引用;如果可被joinable,则terminate报错。
thread& operator= (thread&& rhs) noexcept;

(2)copy[deleted]:
拷贝赋值操作被禁用。
thread& operator= (const thread&) = delete;
  1. 其它成员函数:
· get_id
    获取线程的id。
· joinable
    检查线程是否可被join。
· join
    Join线程。
· detach
    Detach线程。
· swap
    Swap线程。
· native_handle
    返回native handle。
· hardware_concurrency [static]
    检查硬件并发特性。

std::mutex

Mutex系列类:
· std::mutex 最基本的Mutex类
· std::recursive_mutex 递归Mutex类
· std::time_mutex 定时Mutex类
· std::recursive_timed_mutex 定时递归的Mutex类
Lock类:
· std::lock_guard 方便线程对互斥量上锁。
· std::unique_lock 方便线程对互斥量上锁,但提供了更好的上锁和解锁控制。
其他类型类:
· std::once_flag
· std::adopt_lock_t
· std::defer_lock_t
· std::try_to_lock_t
函数:
std::try_lock 尝试同时对多个互斥量上锁。
std::lock 可以同时对多个互斥量上锁。
std::call_once 如果多个线程需要同时调用某个函数,call_once可以保证多个线程对该函数都只调用一次。

第二部分:生产者-消费者问题在Windows环境下的C语言实现

创建n个线程模拟生产者和消费者,并实现进程(线程)的同步与互斥

  1. 一个生产者和一个消费者,对n个资源进行读取和写入操作。
#include <windows.h>
#include <cstdlib>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

const int repositorySize = 10;//产品缓冲区的最大容量
const int itemSize = 200;//生产产品的最大数量

struct ItemRepository {
	int item_buffer[repositorySize];//产品缓冲区
	size_t read_pos = 0;//消费者读取产品的位置 初始化为0
	size_t write_pos = 0;//生产者写入产品的位置 初始化为0
	std::mutex mtx;//互斥量 实现产品缓冲区的互斥
	std::condition_variable repo_not_empty;//条件变量 表示产品缓冲区不为空
	std::condition_variable repo_not_full;//条件变量 表示产品缓冲区不为满
}itemRepository;


void ProduceItem(ItemRepository* repo, int item) {//生产资源
	//进入区
	std::unique_lock<std::mutex> lock(repo->mtx);//上锁
	while ((repo->write_pos + 1) % repositorySize == repo->read_pos) {//产品缓冲区已满
		std::cout << "生产者正在等待缓冲区内产品被消耗\n";
		(repo->repo_not_full).wait(lock);//生产者等待“产品缓冲区不为满”这一条件发生
	}
	//临界区
	repo->item_buffer[repo->write_pos] = item;//写入
	repo->write_pos = (repo->write_pos + 1) % repositorySize;
	//退出区
	repo->repo_not_empty.notify_all();//通知
	lock.unlock();
}

int ConsumeItem(ItemRepository* repo) {//消费资源
	int item;
	//进入区
	std::unique_lock<std::mutex> lock(repo->mtx);//上锁
	while (repo->write_pos == repo->read_pos) {//产品缓冲区为空
		std::cout << "消费者正在等待缓冲区内生产出产品\n";
		repo->repo_not_empty.wait(lock);//消费者等待“产品缓冲区不为空”这一条件发生
	}
	//临界区
	item = repo->item_buffer[repo->read_pos];//读取
	repo->read_pos = (repo->read_pos + 1) % repositorySize;
	//退出区
	repo->repo_not_full.notify_all();//通知
	lock.unlock();
	return item;
}

void Produce() {//生产者
	for (int i = 1; i <= itemSize; i++) {
		Sleep(1);
		std::cout << "正在生产资源\n";
		ProduceItem(&itemRepository, i);
	}
}

void Consume() {//消费者
	for (int i = 1; i <= itemSize; i++) {
		Sleep(1);
		int item = ConsumeItem(&itemRepository);
		std::cout << "正在消费资源\n";
	}
}

int main() {
	std::thread producer(Produce);
	std::thread consumer(Consume);
	producer.join();
	consumer.join();
	return 0;
}
  1. n个生产者和n个消费者,对n个资源进行读取和写入操作。
#pragma warning (disable:4996)
#include <windows.h>
#include <cstdlib>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>

const int repositorySize = 5;//产品缓冲区的最大容量
const int itemSize = 20;//生产产品的最大数量

struct ItemRepository {
	int item_buffer[repositorySize];//产品缓冲区
	size_t read_pos = 0;//消费者读取产品的位置 初始化为0
	size_t write_pos = 0;//生产者写入产品的位置 初始化为0
	size_t produced_cnt = 0;//生产者计数
	size_t consumed_cnt = 0;//消费者计数
	std::mutex mtx;//互斥量 实现产品缓冲区的互斥
	std::mutex producer_mutex;//互斥量 实现生产者的互斥
	std::mutex consumer_mutex;//互斥量 实现消费者的互斥
	std::condition_variable repo_not_empty;//条件变量 表示产品缓冲区不为空
	std::condition_variable repo_not_full;//条件变量 表示产品缓冲区不为满
}itemRepository;


void ProduceItem(ItemRepository* repo, int item) {//生产资源
	//进入区
	std::unique_lock<std::mutex> lock(repo->mtx);//上锁
	while ((repo->write_pos + 1) % repositorySize == repo->read_pos) {//产品缓冲区已满
		std::cout << "生产者正在等待缓冲区内产品被消耗\n";
		(repo->repo_not_full).wait(lock);//生产者等待“产品缓冲区不为满”这一条件发生
	}
	//临界区
	repo->item_buffer[repo->write_pos] = item;//写入
	repo->write_pos = (repo->write_pos + 1) % repositorySize;
	//退出区
	repo->repo_not_empty.notify_all();//通知
	lock.unlock();
}

int ConsumeItem(ItemRepository* repo) {//消费资源
	int item;
	//进入区
	std::unique_lock<std::mutex> lock(repo->mtx);//上锁
	while (repo->write_pos == repo->read_pos) {//产品缓冲区为空
		std::cout << "消费者正在等待缓冲区内生产出产品\n";
		repo->repo_not_empty.wait(lock);//消费者等待“产品缓冲区不为空”这一条件发生
	}
	//临界区
	item = repo->item_buffer[repo->read_pos];//读取
	repo->read_pos = (repo->read_pos + 1) % repositorySize;
	//退出区
	repo->repo_not_full.notify_all();//通知
	lock.unlock();
	return item;
}

void Produce() {//生产者
	bool ready_to_exit = false;
	for (int i = 1; i <= itemSize; i++) {
		Sleep(1);
		std::unique_lock<std::mutex> lock(itemRepository.producer_mutex);
		if (itemRepository.produced_cnt < repositorySize) {
			itemRepository.produced_cnt++;
			ProduceItem(&itemRepository, itemRepository.produced_cnt);
			std::cout << "正在生产资源\n";
		}
		else
			ready_to_exit = true;
		lock.unlock();
		if (ready_to_exit)
			break;
	}
}

void Consume() {//消费者
	bool ready_to_exit = false;
	for (int i = 1; i <= itemSize; i++) {
		Sleep(1);
		std::unique_lock<std::mutex> lock(itemRepository.consumer_mutex);
		if (itemRepository.consumed_cnt < repositorySize) {
			int item = ConsumeItem(&itemRepository);
			itemRepository.consumed_cnt++;
			std::cout << "正在消费资源\n";
		}
		else
			ready_to_exit = true;
		lock.unlock();
		if (ready_to_exit)
			break;
	}
}

int main() {
	std::thread producer1(Produce);
	std::thread producer2(Produce);
	std::thread producer3(Produce);
	std::thread producer4(Produce);
	std::thread consumer1(Consume);
	std::thread consumer2(Consume);
	std::thread consumer3(Consume);
	std::thread consumer4(Consume);
	producer1.join();
	producer2.join();
	producer3.join();
	producer4.join();
	consumer1.join();
	consumer2.join();
	consumer3.join();
	consumer4.join();
	return 0;
}

第三部分:读者-写者问题在Windows环境下的C语言实现

读者优先

#pragma once
#include<mutex>
#include<condition_variable>
#include<iostream>
#include<vector>
#include<thread>
#include <windows.h>

struct ReadWriteLock {
	int readWaiting = 0;  //等待读
	int writeWaiting = 0; //等待写
	int reading = 0; //正在读
	int writing = 0;  //正在写
	std::mutex mx;
	std::condition_variable cond;
}readwriteLock;

void readLock(ReadWriteLock* readwriteLock) {
	std::unique_lock<std::mutex>lock(readwriteLock->mx);
	readwriteLock->readWaiting++;
	while (readwriteLock->writing > 0) {//读者优先
		std::cout << "读进程正在等待\n";
		readwriteLock->cond.wait(lock);
	}
	readwriteLock->reading++;
	readwriteLock->readWaiting--;
}

void writeLock(ReadWriteLock* readwriteLock) {
	std::unique_lock<std::mutex>lock(readwriteLock->mx);
	readwriteLock->writeWaiting++;
	while (readwriteLock->reading > 0 || readwriteLock->writing > 0) {
		std::cout << "写进程正在等待\n";
		readwriteLock->cond.wait(lock);
	}
	readwriteLock->writing++;
	readwriteLock->writeWaiting--;
}

void readUnLock(ReadWriteLock* readwriteLock) {
	std::unique_lock<std::mutex>lock(readwriteLock->mx);
	readwriteLock->reading--;
	if (readwriteLock->reading <= 0)
		readwriteLock->cond.notify_one();//当前没有读者时,唤醒一个写者
}

void writeUnLock(ReadWriteLock* readwriteLock) {
	std::unique_lock<std::mutex>lock(readwriteLock->mx);
	readwriteLock->writing--;
	readwriteLock->cond.notify_all();//唤醒所有读者、写者
}

void Reader() {
	readLock(&readwriteLock);
	std::cout << "读进程正在执行\n";
	Sleep(1);
	readUnLock(&readwriteLock);
}

void Writer() {
	writeLock(&readwriteLock);
	std::cout << "写进程正在执行\n";
	Sleep(1);
	writeUnLock(&readwriteLock);
}

int main() {
	std::thread reader1(Reader);
	std::thread reader2(Reader);
	std::thread reader3(Reader);
	std::thread reader4(Reader);
	std::thread writer1(Writer);
	std::thread writer2(Writer);
	std::thread writer3(Writer);
	std::thread writer4(Writer);
	reader1.join();
	reader2.join();
	reader3.join();
	reader4.join();
	writer1.join();
	writer2.join();
	writer3.join();
	writer4.join();
	return 0;
}

写者优先

#pragma once
#include<mutex>
#include<condition_variable>
#include<iostream>
#include<vector>
#include<thread>
#include <windows.h>

struct ReadWriteLock {
	int readWaiting = 0;  //等待读
	int writeWaiting = 0; //等待写
	int reading = 0; //正在读
	int writing = 0;  //正在写
	std::mutex mx;
	std::condition_variable cond;
}readwriteLock;

void readLock(ReadWriteLock* readwriteLock) {
	std::unique_lock<std::mutex>lock(readwriteLock->mx);
	readwriteLock->readWaiting++;
	while (readwriteLock->writing > 0 || readwriteLock->writeWaiting > 0) {//写者优先
		std::cout << "读进程正在等待\n";
		readwriteLock->cond.wait(lock);
	}
	readwriteLock->reading++;
	readwriteLock->readWaiting--;
}

void writeLock(ReadWriteLock* readwriteLock) {
	std::unique_lock<std::mutex>lock(readwriteLock->mx);
	readwriteLock->writeWaiting++;
	while (readwriteLock->reading > 0 || readwriteLock->writing > 0) {
		std::cout << "写进程正在等待\n";
		readwriteLock->cond.wait(lock);
	}
	readwriteLock->writing++;
	readwriteLock->writeWaiting--;
}

void readUnLock(ReadWriteLock* readwriteLock) {
	std::unique_lock<std::mutex>lock(readwriteLock->mx);
	readwriteLock->reading--;
	if (readwriteLock->reading <= 0)
		readwriteLock->cond.notify_one();//当前没有读者时,唤醒一个写者
}

void writeUnLock(ReadWriteLock* readwriteLock) {
	std::unique_lock<std::mutex>lock(readwriteLock->mx);
	readwriteLock->writing--;
	readwriteLock->cond.notify_all();//唤醒所有读者、写者
}

void Reader() {
	readLock(&readwriteLock);
	std::cout << "读进程正在执行\n";
	Sleep(1);
	readUnLock(&readwriteLock);
}

void Writer() {
	writeLock(&readwriteLock);
	std::cout << "写进程正在执行\n";
	Sleep(1);
	writeUnLock(&readwriteLock);
}

int main() {
	std::thread reader1(Reader);
	std::thread reader2(Reader);
	std::thread reader3(Reader);
	std::thread reader4(Reader);
	std::thread writer1(Writer);
	std::thread writer2(Writer);
	std::thread writer3(Writer);
	std::thread writer4(Writer);
	reader1.join();
	reader2.join();
	reader3.join();
	reader4.join();
	writer1.join();
	writer2.join();
	writer3.join();
	writer4.join();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值