操作系统实验:消费者-生产者问题

  • README
  • 一、实验目的
  • 二、实验内容
  • 三、实验步骤
  • 四、主要数据结构及其说明
  • 五、程序运行时的初值和运行结果
  • 六、实验体会
  • 七、源程序

README

本实验报告仅供参考,请勿直接抄袭!

一、实验目的

通过实验,掌握 Windows 和 Linux 环境下互斥锁和信号量的实现方法,加深对临界区问题和进程同步机制的理解,同时熟悉利用 Windows API 和 Pthread API 进行多线程编程的方法。

二、实验内容

  1. 在 Windows 操作系统上,利用 Win32 API 提供的信号量机制,编写应用 程序实现生产者——消费者问题。
  2. 在 Linux 操作系统上,利用 Pthread API 提供的信号量机制,编写应用程序实现生产者——消费者问题。
  3. 两种环境下,生产者和消费者均作为独立线程,并通过 empty、full、mutex 三个信号量实现对缓冲进行插入与删除。
  4. 通过打印缓冲区中的内容至屏幕,来验证应用程序的正确性。 具体内容可参见“Operating System Concepts (Seventh Edition)” Chapter 6 后的 Project(P236-241)。

三、实验步骤

  1. 首先写出解决生产者——消费者问题的伪代码,如下图所示:
  2. 查阅Win32 API提供的信号量机制和Pthread API提供的信号量机制,掌握HANDLE、CreateSemaphore、WaitForSingleObject、ReleaseSemaphore、CreateThread和sem_t、sem_init、sem_wait、sem_post、pthread_create等变量和函数的用法;
  3. 将第1步中的伪代码实现成可运行的代码:首先声明三个信号量——互斥信号量Mutex、计数信号量Empty和计数信号量Full,再声明缓冲区Buffer(1代表该位置有产品,0代表该位置没有产品),其大小为SizeOfBuffer,其中Empty的初始值为SizeOfBuffer,Full的初始值为0,Mutex的初始值为1;然后分别根据伪代码实现生产者线程produce和消费者线程consume;最后在main()中创建多线程——5个生产者和5个生产者,并使主线程等待一定时间;

四、主要数据结构及其说明

  1. HANDLE:初始化函数为 HANDLE CreateSemaphore(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount, LPCTSTR lpName),其中第一个参数表示安全控制,一般直接传入NULL,第二个参数表示初始资源数量,第三个参数表示最大并发数量,第四个参数表示信号量名称,传入NULL表示匿名信号量,返回值为创建好的HANDLE;
    wait操作为DWORD WaitForSingleObject(HANDLE hHandle, DWORDdwMilliseconds),其中第一个参数为要等待的HANDLE,第二个参数为Timeout时间,一般设为最大值INFINITE;
    signal操作为BOOL ReleaseSemaphore(HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount),其中第一个参数为被操作的信号量,第二个参数为增加的值,第三 个参数为指向返回信号量上次值的变量的指针,如果不需要信号量上次的值,那么这个参数可以设置为NULL,该函数如果成功返回TRUE,否则返回FALSE;
  2. sem_t:初始化函数为int sem_init(sem_t *sem, int pshared, unsigned int value),其 中第一个参数为需要初始化的sem_t的地址,第二个参数决定了信号量能否在进程之间共享,第三个参数为该信号量值的大小;
    wai操作为int sem_wait(sem_t * sem),参数为需要操作的信号量,该函数成功返回0,失败的话信号量的值不变,返回-1;
    signal操作为int sem_post(sem_t *sem),参数为需要操作的信号量,该函数成功返回0,失败 的话信号量的值不变,返回-1;

五、程序运行时的初值和运行结果

  • Windows操作系统:

  • Linux操作系统:

六、实验体会

实验中产生的错误以及原因分析以及解决过程:在Linux操作系统下使用终端运行程序时,输出文件中总是提示“段错误(核心已转储)”。在CSDN上查阅了相关资料后,首先推断可能是栈空间大小不足,于是在终端中使用ulimit -c unlimited和ulimit -s 819200两条指令扩大源文件大小以及栈空间大小。再次编译运行,发现依然出现相同的问题。排除了栈空间不足这个原因之后,推断可能是访问了不存在的内存地址,即指针越界。于是逐行检查各个涉及到指针的代码的运行状况。最后发现是刚开始的时候为图方便,在没有查看函数参数含义的情况下,直接将创建线程的函数写为了pthread_create(NULL, NULL, produce, NULL),而该函数的前两个参数是不能为NULL的,否则就会出现指针越界。将此处代码修改后,再次编译运行,发现可以正确运行了!

实验的体会及收获:不可以为求省事就不查看函数的参数列表以及每个参数的取值范围,否则就会出现很难排查出来的错误。幸好此次试验的代码体量较小,只有大约100行左右,排查错误较为简单。然而,如果是在大型实验中,像本次这种指针越界的Bug,是非常难排查出来的。所以,在今后的实验中,我不能再犯这种低级错误!

七、源程序

  • OnWindows:
#include<iostream>
#include<stdio.h>
#include<windows.h>
using namespace std;HANDLE Mutex;//互斥信号
HANDLE Full;//计数信号 ,代表目前缓冲区内有几个位置已满
HANDLE Empty;//计数信号 ,代表目前缓冲区内有几个位置是空的
const int SizeOfBuffer = 10;//缓冲区的大小,即有几个位置
int* Buffer;//缓冲区//显示缓冲区当前的存储情况
void showBuffer()
{cout << "目前缓冲区的存储情况:";for (int i = 0; i < SizeOfBuffer; ++i){cout << Buffer[i] << " ";}cout << endl;
}//生产者线程
DWORD WINAPI produce(LPVOID param)
{do{WaitForSingleObject(Empty, INFINITE);//等待缓冲区中有空位WaitForSingleObject(Mutex, INFINITE);//对缓冲区形成互斥访问//寻找缓冲区里面的一个空位置for (int i = 0; i < SizeOfBuffer; ++i){if (Buffer[i] == 0){Buffer[i] = 1;//放置产品cout<<"ID为"<<GetCurrentThreadId()<<"的生产者在缓冲区的 第"<<i<<"个位置放置一个产品"<<endl;showBuffer();break;}}ReleaseSemaphore(Mutex, 1, NULL);//释放互斥信号量MutexReleaseSemaphore(Full, 1, NULL);//使Full加一} while (true);return 0;
}//消费者线程
DWORD WINAPI consume(LPVOID param)
{do{WaitForSingleObject(Full, INFINITE);//等待缓冲区中有产品WaitForSingleObject(Mutex, INFINITE);//对缓冲区形成互斥访问//寻找缓冲区里面的一个有产品的位置for (int i = 0; i < SizeOfBuffer; ++i){if (Buffer[i] == 1){Buffer[i] = 0;//»°◊fl≤˙∆∑cout << "ID为" << GetCurrentThreadId() << "的消费者在缓冲区的第" << i << "个位置取走了一个产品" << endl;showBuffer();break;}}ReleaseSemaphore(Mutex, 1, NULL);//释放互斥信号量MutexReleaseSemaphore(Empty, 1, NULL);//使Empty加一} while (true);return 0;
}int main()
{Empty = CreateSemaphore(NULL, 10, 10, NULL);//初始化Empty,初始值设为10,最大值为10Full = CreateSemaphore(NULL, 0, 10, NULL);//初始化Full,初始值设为0,最大值为10Mutex = CreateSemaphore(NULL, 1, 1, NULL);//初始化Mutex,初始值设为1//初始化缓冲区Buffer = new int[SizeOfBuffer];for (int i = 0; i < SizeOfBuffer; ++i){Buffer[i] = 0;}//创建5个生产者线程和5个消费者线程for (int i = 0; i < 5; ++i){CreateThread(NULL, 0, consume, NULL, 0, NULL);CreateThread(NULL, 0, produce, NULL, 0, NULL);}//让主线程等待一定的时间Sleep(1000);
}
  • OnLinux:
#include<pthread.h>
#include<semaphore.h>
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
#include<unistd.h>
#include<semaphore.h>//缓冲区的大小,即有几个位置
#define SizeOfBuffer 5sem_t Mutex;//互斥信号量
sem_t Full;//计数信号量,代表目前缓冲区内有几个位置已满
sem_t Empty;//计数信号量,代表目前缓冲区内有几个位置为空
int *Buffer;//缓冲区,1代表有产品,0代表没有产品//显示缓冲区当前的存储情况
void showBuffer()
{printf("\t缓冲区:");for(int i = 0; i < SizeOfBuffer; ++i){printf("%d", Buffer[i]);printf(" ");}printf("\n");
}//生产者线程
void *produce(void *arg)
{do{sem_wait(&Empty);//等待缓冲区中有空位sem_wait(&Mutex);//对缓冲区形成互斥访问//寻找缓冲区里面的一个空位置for(int i = 0; i < SizeOfBuffer; ++i){if(Buffer[i] == 0){Buffer[i] = 1;//放置产品printf("%s%lu%s%d%s", "ID为", pthread_self(), "的生产者在缓冲区的第", i, "个位置放置了一个产品");showBuffer();break;}}sem_post(&Mutex);//释放互斥信号量Mutexsem_post(&Full);//使Full加1}while(true);
}//消费者线程
void *consume(void *arg)
{do{sem_wait(&Full);//等待缓冲区中有空位sem_wait(&Mutex);//对缓冲区形成互斥访问//寻找缓冲区里面的一个产品for(int i = 0; i < SizeOfBuffer; ++i){if(Buffer[i] == 1){Buffer[i] = 0;//取走产品printf("%s%lu%s%d%s", "ID为", pthread_self(), "的消费者在缓冲区的第", i, "个位置取走了一个产品");showBuffer();break;}}sem_post(&Mutex);//释放互斥信号量Mutexsem_post(&Empty);//使Empty加1}while(true);
}int main()
{//初始化Buffer数组Buffer = (int*)malloc(SizeOfBuffer*sizeof(int*));//Buffer = new int[SizeOfBuffer];for(int i = 0; i < SizeOfBuffer; ++i){Buffer[i] = 0;}sem_init(&Mutex, 1, 1);//初始化Mutex为1sem_init(&Empty, 0, 10);//初始化Empty为10sem_init(&Full, 0, 0);//初始化Full为0pthread_t tid[10];pthread_attr_t attr;pthread_attr_init(&attr);//创建5个消费者线程和5个生产者线程for(int i = 0; i < SizeOfBuffer; ++i){pthread_create(&tid[i], &attr, consume, NULL);pthread_create(&tid[i + 5], &attr, produce, NULL);}sleep(0.999);return 0;
}

【SEUSE】操作系统实验:消费者-生产者问题相关推荐

  1. 操作系统实验之生产者和消费者程序

    这是我的操作系统实验课的实验之一,实验要求"实现生产者和消费者程序". 老师给了我们示例程序,要求我们自己修改调试.程序代码如下,已经在本地linux系统上能够正确运行. p是模拟 ...

  2. 操作系统实验二·生产者消费者问题

    生产者消费者问题 1实验目的 2实验内容 3实验环境 3.1Windows 3.2Linux虚拟机 4程序设计和实现 4.1Windows实现 4.1.1函数解释 4.1.2程序代码 4.1.3运行结 ...

  3. Linux操作系统实验:生产者和消费者问题

    一.实验目的及要求 "生产者消费者"问题是一个著名的同时性编程问题的集合.通过编写经典的"生产者消费者"问题的实验,读者可以进一步熟悉 Linux 中多线程编程 ...

  4. 2021-11-02 操作系统实验3——生产者消费者实验

    文章目录 一.实验目的 二.实验任务 三.实验要求 四.实验过程 五.实验测试 一.实验目的 了解和熟悉linux系统下的信号量集和共享内存. 二.实验任务 使用linux系统提供的信号量集和共享内存 ...

  5. 操作系统实验 生产者消费者问题详解

    操作系统课程设计 生产者消费者实验报告 一.实验目的 加深对进程概念的理解,明确进程与程序的区别. 认识并发执行的本质. 理解和掌握Linux和Windows进程通信系统调用的功能,通过实验和学习,提 ...

  6. c语言生产者与消费者实验报告,生产者和消费者实验报告.doc

    生产者和消费者实验报告 [实验目的] 加深对进程概念的理解,明确进程和程序的区别. 进一步认识并发执行的实质. 验证用信号量机制实现进程互斥的方法. 验证用信号量机制实现进程同步的方法. [实验要求] ...

  7. 操作系统中消费者与生产者的同步互斥问题

    在操作系统中,我们有进程,进程会占用资源,有些资源是可以共享的,但有些资源是只允许一个占用,不能共享,只有当占用的线程用完释放后,下一个需要用的线程才可以申请使用,这样的资源便是临界资源.属于临界资源 ...

  8. C语言生产者消费者实验报告,生产者与消费者实验报告.doc

    生产者与消费者实验报告.doc 生产者和消费者实验报告[实验目的]1. 加深对进程概念的理解,明确进程和程序的区别.2. 进一步认识并发执行的实质.3. 验证用信号量机制实现进程互斥的方法.4. 验证 ...

  9. 操作系统实验报告15:进程同步与互斥线程池

    操作系统实验报告15 实验内容 实验内容:进程同步. 内容1:编译运行课件 Lecture18 例程代码. Algorithms 18-1 ~ 18-9. 内容2:在 Lab Week 13 的基础上 ...

最新文章

  1. python程序设计课后答案祁瑞华_清华大学出版社-图书详情-《Python 程序设计》
  2. Java2WSDL 和 WSDL2Java(Axis)
  3. hive修改 表/分区语句
  4. 学习笔记——Numpy基本操作(二)
  5. mount: unknown filesystem type 'smbfs' 问题解决
  6. java鼠标经过时变色_将鼠标悬停在标签上时,鼠标指针会变为手形
  7. php xxtea加密,php - esp32和php XXTEA字符串加密 - SO中文参考 - www.soinside.com
  8. 什么是协议转换器?协议转换器的定义
  9. 太硬核!2亿股万科股票,约53亿元,一次性全部捐给清华,干一件大事!
  10. (数据库系统概论|王珊)第三章关系数据库标准语言SQL-第六、七节:视图
  11. vue 导入excel插件_Vue框架下实现导入导出Excel、导出PDF
  12. Tomcat局域网多端口建立多网站
  13. 机器学习分类算法综述
  14. 【转】windows上安装gvim
  15. 九、Linux系统安装和常见故障排除
  16. 阶段3 2.Spring_10.Spring中事务控制_3 作业-基于注解的AOP实现事务控制及问题分析_下...
  17. UBUNTU16.04下Teamviewer的安装
  18. java网上在线考试系统代码_Java+JavaWeb在线考试系统
  19. APP下载页源码-带后台
  20. python算法入门

热门文章

  1. 老生常谈:项目管理之时间管理
  2. 【Android】Android自动开关机实现
  3. 在线未注册域名批量查询-域名注册批量查询
  4. Python判断文件是否存在
  5. 计算机视觉学习7_多视图几何_基础矩阵
  6. freebsd linux双系统,多系统安装实践(Window /FreeBSD/Linux) (转)
  7. 网卡或网络配置文件(Linux网络操作系统与管理配置)小红帽
  8. mysql查找字符第n次出现位置_查找字符在字符串中第N次出现的位置
  9. 学生管理系统登录界面/接口---简单前后端连接
  10. 车牌识别系统电脑当服务器,车牌识别系统数据库的安装方法