操作系统-进程同步:生产者-消费者问题

这篇具有很好参考价值的文章主要介绍了操作系统-进程同步:生产者-消费者问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

进程同步:生产者-消费者问题

问题描述

​ 以生产者-消费者模型为基础,在Windows环境下创建一个控制台进程(或者界面进程),在该进程中创建读者写者线程模拟生产者和消费者。写者线程写入数据,然后将数据放置在一个空缓冲区中供读者线程读取。读者线程从缓冲区中获得数据,然后释放缓冲区。当写者线程写入数据时,如果没有空缓冲区可用,那么写者线程必须等待读者线程释放出一个空缓冲区。当读者线程读取数据时,如果没有满的缓冲区,那么读入线程将被阻塞,直到新的数据被写进去。

​ 实验要求设计并实现一个进程,该进程拥有一个生产者线程和一个消费者线程,它们使用N个不同的缓冲区(N为一个确定的数值,本实验中取N=16)。可以作如下的实验尝试,并观察和记录进程同步效果:

(1) 没有信号量时实现生产者线程与消费者线程互斥制约。

(2) 用以下信号量实现生产者线程与消费者线程互斥制约:

创建临界区,用以阻止生产者线程和消费者线程同时操作缓冲区列表,功能同互斥信号量。

(3) 用以下信号量实现生产者线程与消费者线程的同步制约:

一个信号量full,当生产者线程生产出一个物品时可以用它向消费者线程发出信号。

一个信号量empty,消费者线程释放出一个空缓冲区时可以用它向生产者线程发出信号。

(4) 同时使用(2)(3)中的信号量实现生产者-消费者的互斥与同步制约。

实验环境

  • Windows 11
  • Visual Studio Code
  • GCC version 8.1.0

输入

  • 创建1个生产者线程和1个消费者线程,设定缓冲区大小为16,观察运行结果。

输出

  • 生产者每生产一个资源,剩余资源就加一,最高到16,则停止生产;消费者每消费一个资源,剩余资源就减一,最低到0,则停止消费。

测试数据

生产者数量 消费者数量 缓冲区大小
1 1 16
  • 测试两种不同情况:缓冲区满和缓冲区空

    • 缓冲区满:生产者线程睡眠时间短于消费者,则一段时间后会导致缓冲区满;

    • 缓冲区空:生产者线程睡眠时间长于消费者,则一段时间后会导致缓冲区空。

实验设计

数据结构

//缓冲区大小
#define N 16
//使用临界区来同步线程
CRITICAL_SECTION cr;
//空信号量
HANDLE emptySemaphore = NULL;
//满信号量
HANDLE fullSemaphore = NULL;
//缓冲区
vector<int> buffer;

系统框架图

操作系统-进程同步:生产者-消费者问题

流程图

操作系统-进程同步:生产者-消费者问题

实验结果与分析

结果展示与描述

  • 生产速度大于消费速度:

操作系统-进程同步:生产者-消费者问题

操作系统-进程同步:生产者-消费者问题

  • 生产速度小于消费速度:

操作系统-进程同步:生产者-消费者问题文章来源地址https://www.toymoban.com/news/detail-419051.html

结果分析

  • 首先创建了empty和full2个信号量以及临界区用来实现进程同步问题,生产者不断生产资源,缓冲区大小为16,缓冲区满时停止生产。只有缓冲区有内容时,消费者才能执行他的动作。
  • 生产速度大于消费速度时,一段时间后缓冲区满,生产者停止生产,等到消费者取出一个资源时,生产者再继续生产,因此资源最终在15和16之间跳动;
  • 生产速度小于消费速度时,缓冲区空时消费者停止消费,等到生产者生产一个资源时,消费者再继续消费,因此资源会在0和1之间跳动。

总结

  • 编写多线程程序时,有时不可避免的需要在多个线程之间传递数据,就可能出现多个线程同时访问同一个资源的情况,这时就需要线程间的通信,解决同步与互斥的问题。
  • 本实验在Windows环境下,使用临界区的方式实现线程间的互斥。本实验共有1个生产者和1个消费者,结果表明生产者与消费者之间并没有产生矛盾,资源的增加与减少都符合规律。

源代码

#include <iostream>
#include <Windows.h>
#include <process.h>
#include <vector>
using namespace std;
// 等价于WINAPI,约定使用stdcall函数调用,既被调用者负责清栈
#define STD __stdcall
//缓冲区大小
#define N 16
#define GETMYRAND() (int)(((double)rand() / (double)RAND_MAX) * 3000)
//使用临界区来同步线程
CRITICAL_SECTION cr;
//空信号量
HANDLE emptySemaphore = NULL;
//满信号量
HANDLE fullSemaphore = NULL;
//缓冲区
vector<int> buffer;

//消费者线程
DWORD STD Consumer(void *lp)
{
	while (true)
	{
		//等待判断缓冲区满信号量
		WaitForSingleObject(fullSemaphore, 0xFFFFFFFF);
		//进入临界区,线程同步,功能同互斥量
		EnterCriticalSection(&cr);
		//消费者线程从缓冲区取出消费一个资源
		buffer.pop_back();
		//打印当前缓冲区可用资源数
		cout << "消费一个资源,当前可用资源数:" << buffer.size() << endl;
		//离开临界区
		LeaveCriticalSection(&cr);
		//释放判断缓冲区空的信号量
		ReleaseSemaphore(emptySemaphore, 1, NULL);
		//线程睡眠随机时间
		Sleep(GETMYRAND() + 2000);
	}
	return 0;
}

//生产者线程
DWORD STD Producer(void *lp)
{
	while (true)
	{
		//等待判断缓冲区空信号量
		WaitForSingleObject(emptySemaphore, 0xFFFFFFFF);
		//进入临界区,线程同步,功能互斥量
		EnterCriticalSection(&cr);
		//生产者线程向缓冲区中生成一个资源
		buffer.push_back(1);
		//打印当前缓冲区可用资源数
		cout << "生产一个新资源,当前可用资源数:" << buffer.size() << endl;
		//离开临界区
		LeaveCriticalSection(&cr);
		//释放判断缓冲区满信号量
		ReleaseSemaphore(fullSemaphore, 1, NULL);
		//线程睡眠随机时间
		Sleep(GETMYRAND() + 200);
	}
	return 0;
}

// 主函数
int main()
{
	//创建信号量
	emptySemaphore = CreateSemaphore(NULL, N, N, NULL);
	fullSemaphore = CreateSemaphoreW(NULL, 0, N, NULL);
	//初始化临界区
	InitializeCriticalSection(&cr);
	//开启多线程
	HANDLE handles[2];
	handles[1] = CreateThread(0, 0, &Producer, 0, 0, 0);
	handles[0] = CreateThread(0, 0, &Consumer, 0, 0, 0);
	//等待子线程执行完毕
	WaitForMultipleObjects(2, handles, true, INFINITE);
	//释放子线程
	CloseHandle(handles[0]);
	CloseHandle(handles[1]);
	//释放临界区
	DeleteCriticalSection(&cr);
	return 0;
}

到了这里,关于操作系统-进程同步:生产者-消费者问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包