♻️ 资源大小5.62MB➡️资源下载https://download.csdn.net/download/s1t16/87450290生产者消费者问题实验目的使用进程模拟消费者生产者进程掌握进程之间的通信方法区分在不同操作系统下进程通信的不同之处并熟练使用信号量的创建删除等一系列操作实验内容一个大小为 3 的缓冲区初始为空个生产者随机等待一段时间往缓冲区添加数据若缓冲区已满等待消费者取走数据后再添加重复 6 次随机等待一段时间从缓冲区读取数据若缓冲区为空等待生产者添加数据后再读取重复 4 次说明显示每次添加和读取数据的时间及缓冲区里的数据指缓冲区里的具体内容生产者和消费者用进程模拟不能用线程Linux/Window 下都需要做一、实验环境WindowsWindows10处理器 Inter core i5-8265u1.60GHzmailto:i5-8265u1.60GHz 内存 8.00GB系统类型 64 位操作系统基于 x64 的处理器Linux虚拟机软件VMware workstation 15虚拟机操作系统Ubuntu20.04 虚拟机内存4GB二、虚拟机硬盘容量:60GB 四、 程序设计与实现在 Windows 下的实现要实现生产者消费者模型的模拟首先要创建文件缓冲区在 Windows 中通过文件映射的方式来实现创建缓冲区。定义缓冲区结构定义共享内存的结构2.1 然后使用 GreateFileMapping()创建文件映射对象,API 的解释如下返回一个文件对象句柄通过文件对象句柄对该映射对象进行初始化等一系列操作在主函数中根据不同的进程号判断是消费者进程还是生成者进程并采取不同的操作在主进程中先创建映射视图和信号量并初始化MapViewOfFile () 用于将视图映射到创建的共享文件API 的解释如下参数hFileMappingObject 文件映射对象的句柄dwDesiredAccess 文件映射对象的访问类型取值为FILE_MAP_ALL_ACCESS 表示对映射文件对象有读写的权利 dwFileOffsetHigh 文件高阶偏移量dwFileOffsetLow 文件低阶偏移量dwNumberOfBytesToMap 映射到视图的文件映射的字节数CreateSemaphore() 此 API 用于创建或打开一个信号量具体解释如下参数lpSemaphoreAttributes为信号量的属性一般可以设置为 NULLlInitialCount 信号量初始值必须大于等于 0 而且小于等于 lpMaximumCount如果 lInitialCount 的初始值为 0则该信号量默认为 unsignal 状态如果 lInitialCount 的初始值大于 0则该信号量默认为 signal 状态lMaximumCount 此值为设置信号量的最大值必须大于 0lpName信号量的名字长度不能超出 MAX_PATH 可设置为 NULL表示无名的信号量。当 lpName 不为空时可创建有名的信号量若当前信号量名与已存在的信号量的名字相同时则该函数表示打开该信号量这时参数 lInitialCount 和 lMaximumCount 将被忽略。在 main 函数的主线程中创建缓冲区和信号量并初始化在生产者进程中首先使用 OpenFileMapping()此 API 的作用是打开一个命名的文件映射对象。该 API 的详细解释如下OpenFileMapping ( ByVal dwDesiredAccess As Long, //带有前缀 FILE_MAP_???的常数 ByVal bInheritHandle As Long, //如这个函数返回的句柄能由当前进程启动的新进程继承则这个参数为TRUE ByVal lpName As String //指定要打开的文件映射对象名称 )打开共享内存区后再使用 MapViewOfFile()将共享内存区映射到当前进程的地址空间。MapViewOfFile()的作用是将一个文件映射对象映射到当前的应用程序的地址空间该 API 的解释如下参数hFileMappingObject 文件映射对象的句柄dwDesiredAccess 对文件映射对象的访问类型dwFileOffsetHigh 视图开始处文件的高阶偏移量dwFileOffsetLow 视图开始处文件的低阶偏移量dwNumberOfBytesToMap 映射到视图的字节数。如果此参数为 0零则映射将从指定的偏移量扩展到文件映射的末尾。相关部分代码如下然后使用 OpenSemaphore()打开信号量并对信号量进行初始化在每一次写操作先调用生成随机数的函数返回的随机数作为生产者写入缓冲区的数据同时也作为进程运行前随机睡眠的时间。使用 WaitforSingleObject 来实现信号量的 p 操作相对应的最后通过 ReleaseSemaphore()来实现对信号量的 v 操作然后关闭视图断开与共享内存之间的连接在消费者进程中大致的步骤与生产者进程一样要注意的是对信号量的操作是不同的实验运行结果实验结果成功在 Windows 下使用进程模拟了生产者消费者模型在 Linux 下的实现首先定义缓冲区结构然后使用 semget()创建信号量集其中包含 SEM_FULLSEM_EMPTY2.1.1 SEM_MUTEX 三个信号量并使用 semtcl()对信号量进行初始化接着使用 shmget()创建共享内存区改 API 的具体解释如下key 非 0 整数为共享内存段命名 size 以字节为单位指定需要共享的内存容量shmflg 权限标志它的作用与 open 函数的 mode 参数一样如果要想在 key 标识的共享内存不存在时创建它的话可以与 IPC_CREAT 做或操作。相关代码如图再使用 shmat()函数将创建的共享内存区连接到父进程的地址空间上然后初始化缓冲区。shmat()API 的解释如下该函数作用是用来启动对共享内存的访问并把共享内存连接到当前进程的地址空间参数shm_id 由 shmget()函数返回的共享内存标识。shm_addr 指定共享内存连接到当前进程中的地址位置通常为空表示让系统来选择共享内存的地址。shm_flg 一组标志位通常为 0。部分相关代码如图信号量和缓冲区创建到这里就已经完成了接下来是消费者和生产者进程。首先源码中的 p 操作和 v 操作部分代码如图在生产者进程中首先使用 shmat()函数将共享内存连接到生产者进程的地址空间上然后在依次对 SEM_EMPTY 和 SEM_MUTEX 进行 p 操作随机睡眠一段时间后向缓冲区写入数据完成操作后对 SEM_FULL 和 SEM_MUTEX 进行 v 操作并断开共享内存和进程之间的连接消费者进程与生产者进程基本的操作一致也是先将共享内存和进程的地址空间进行连接不过这里是对 SEM_FULL 和 SEM_EMPTY 先后进行 p 操作随机睡眠一段时间后从缓冲区取出数据最后再对 SEM_EMPTY 和 SEM_MUTEX 进行 v 操作然后断开共享内存的连接最后在所有的子进程运行结束后父进程要删除信号量集和共享内存实验运行结果如图实验结果在 Linux 下成功用线程模拟了生产者消费者模型三、实验收获与体会通过本次实验我对 Windows 和 Linux 下的进程通信有了更加深入的认识同时也熟悉了相关 API共享内存区和信号量的使用。而且在操作实践中对消费者生产者这个经典模型有了更加全面的认识掌握它是如何在不同的操作系统中实际运行的对课程的理论知识的认识有了更加坚实的实践基础。