山东大学操作系统实验五理发师问题报告
- 格式:doc
- 大小:329.50 KB
- 文档页数:28
操作系统作业 1-5章软件5班张** 201200301311第一章1.1a.个人的程序或者数据可能遭到窃取多人同时使用时可能造成cpu拥堵b.不能。
所有保护机制都有可能被外人破译,所以共用系统一定没有单独使用系统安全。
1.10(1)现代操作系统是由中断驱动的,中断可以改变对系统的控制权。
中断可以使一些需要立即响应的进程及时得到处理,并且不影响原进程的运行。
(2)陷阱即为异常,是一种软件中断,源于出错。
而中断不一定是出错,可能是来自I/O的一个命令,可能为硬件中断。
(3)用户可以有意生成陷阱。
目的是为了避免一个进程的错误影响到很多进程,如死循环发生时就可以通过陷阱避免影响。
1.12操作系统需要在任何时刻都可被控制,故可以构建的安全的操作系统为:所有用户程序通过软件实现。
所有的程序都有高级编程语言编写,以便所有目标代码都被编译出来1.17a.批处理:具有相似需求的作业被成批的集合起来,并把它们作为一个整体通过一个操作员或自动作业程序装置运行通过计算机。
通过缓冲区,线下操作,后台和多道程序,运用尝试保持 CPU 和 I/O 一直繁忙,从而使得性能被提高。
批处理系统对于运行那些需要较少互动的大型作业十分适用。
它们可以被更迟地提交或获得。
b.交互式:这种系统由许多短期交易构成,并且下一个交易的结果是无法预知的。
从用户提交到等待结果的响应时间应该是比较短的,通常为 1 秒左右。
c.分时:分时系统中,CPU通过在作业之间的切换来执行多个作业,但是由于切换的频率很高,用户可以在程序运行期间与之进行交互。
d.实时:系统能够在限定的时间内提供用户要求的服务。
e.网络:提供给操作系统一个特征,使得其进入网络,比如文件共享。
f.并行:有多个紧密通信的CPU,它们共享计算机总线,有时还有时钟,内存,外设等。
g.分布:这种系统在几个物理处理器中分布式计算,处理器不共享内存或时钟。
每个处理器都有它各自的本地存储器。
它们通过各种通信线路在进行通信,比如:一条高速的总线或一个本地的网络。
课程设计(综合实验)报告( 2015 -- 2016 年度第 1 学期)名称:操作系统综合实验题目:oslab综合实验院系:计算机系班级:学号:学生姓名:指导教师:设计周数:分散进行成绩:日期:2015 年10 月29 日实验1 实验环境的使用一、综合实验的目的与要求熟悉操作系统集成实验环境OS Lab 的基本使用方法。
练习编译、调试EOS 操作系统内核以及EOS 应用程序。
二、实验正文1.启动 OS Lab2.1 执行项目Windows 控制台窗口内容显示2.2 调试项目2.2.1 使用断点中断执行2.2.2 单步调试2.2.2 .3单步调试结果显示:练习使用“逐语句”功能和“跳出”功能2.2.3 查看变量的值快速监视添加监视2.2.4 调用堆栈调用堆栈显示内容进入Func 函数双击 main 函数所在的行表示此函数是当前调用堆栈中的活动函数。
3 新建EOS 内核项目4 EOS 应用程序项目的生成和调试4.1 新建EOS 应用程序项目4.2 调试项目添加断点后单步调试结果显示4.3 查看软盘镜像文件中的内容4.4修改EOS 应用程序项目名称5 退出OS Lab6 保存EOS 内核项目三、综合实验总结或结论思考与练习:1.在哪些情况下应该使用“逐过程”调试,在哪些情况下应该使用“逐语句”调试。
答:逐语句为每执行一行语句,如果碰到函数调用它就会进入到函数里面。
而逐过程碰到函数时不进入函数,把函数调用当成一条语句去执行。
2. 生成EOS SDK 文件夹的目的和作用。
明白文件夹的组织结构和各个文件的来源和作用。
查看EOS 应用程序包含了SDK 文件夹中的哪些头文件,是如何包含的?(1)EOS SDK为应用程序调用系统API提供服务,可作为用户编程中使用的工具包集合。
(2)其主要包括INC头文件LIB文件夹、导入库文件和BIN文件夹、动态链接库、可执行程序、二进制文件。
(3)包含的头文件有:eos.h负责导出API函数,eosdef.h声明负责导出函数类型的定义,error.h负责导出错误码。
操作系统课程设计实验报告(附思考题答案)课程设计(综合实验)报告( 2015 -- 2016 年度第 1 学期)名称:操作系统综合实验题目:oslab综合实验院系:计算机系班级:学号:学生姓名:指导教师:设计周数:分散进行成绩:日期:2015 年10 月29 日一、综合实验的目的与要求1. 理解和掌握操作系统的基本概念、基本组成与工作原理;2. 理解和掌握操作系统中主要功能模块的工作原理及其实现算法;3. 掌握软件模块设计技能;熟悉并能较好地利用软件开发环境独立编程、调试和分析程序运行情况,逐渐形成创新思维和从事系统软件的研究和开发能力。
二、实验正文实验1:实验环境的使用1.1实验目的:1.熟悉操作系统集成实验环境OS Lab 的基本使用方法。
2.练习编译、调试EOS 操作系统内核以及EOS 应用程序。
1.2实验内容:1.启动OS Lab2.学习OS Lab 的基本用法● 新建 Windows 控制台应用程序项目(1)在“文件”菜单中选择“新建”,然后单击“项目”。
(2)在“新建项目”对话框中,选择项目模板“控制台应用程序(c)”。
(3)在“名称”中输入新项目使用的文件夹名称“oslab ”。
(4)在“位置”中输入新项目保存在磁盘上的位置“C:\test ”。
(5)点击“确定”按钮。
● 生成、执行项目●3.EOS 内核项目的生成和调试● 新建 EOS 内核项目并按F7生成项目● 调试项目● 查看软盘镜像文件中的内容、EOS SDK (Software Development Kit )文件夹4.EOS 应用程序项目的生成和调试● 新建 EOS 应用程序项目● 修改 EOS 应用程序项目名称使用断点中断执行查看变量的值5.退出OS Lab6.保存EOS内核项目1.3思考与练习●在实验1中,生成EOS SDK文件夹的目的和作用是什么?答:SDK文件夹中提供了开发EOS应用程序需要的所有文件。
debug文件夹是在使用debug配置生成项目时生成的,其中存放了调试版本的EOS二进制文件。
操作系统课程设计报告学院:计算机科学与技术学院专业:计算机科学与技术班级:20**级*班姓名:***学号:20**********目录一实验平台 (2)二Project1建立线程系统 (2)Task1.1实现KThread.join() (2)1.要求 (2)2.分析 (2)3.方案 (3)4.实现代码 (3)Task1.2利用中断提供原子性,直接实现条件变量 (4)1.要求 (4)2.分析 (5)3.方案 (5)4.实现代码 (5)Task1.3实现waitUntil (7)1.要求 (7)2.分析 (7)3.方案 (7)4.实现代码 (8)Task1.4用条件变量,不使用信号量,实现同步发送接收消息,speak,listen (10)1.要求 (10)2.分析 (10)3.方案 (11)4.实现代码 (11)Task1.5完成PriorityScheduler实现优先级调度 (13)1.要求 (13)2.分析 (13)3.方案 (14)4.实现代码 (14)Task1.6 (17)1.要求 (17)2.分析 (18)3.方案 (19)4.实现代码 (19)三Project2多道程序设计 (27)Task2.1 (27)1.要求 (27)2.分析 (28)3.方案 (28)4.实现代码 (31)Task2.2 (36)1.要求 (36)2.分析 (36)3.方案 (36)4.实现代码 (38)Task2.3 (43)1.要求 (43)2.分析 (43)3.方案 (44)4.实现代码 (45)Task2.4 (47)1.要求 (47)2.分析 (48)3.方案 (48)4.实现代码 (48)一实验平台开发语言:Java开发工具:Eclipse Luna操作系统:Ubuntu14.04二P roject1建立线程系统Task1.1实现KThread.join()1.要求实现Implement KThread.join()函数。
课程实验报告题目计算机操作系统理发师问题姓名潘 *学号 2013 ***年级专业2013级*指导教师彭 * 华201*年1*月 30 日一题目假设有个理发店,只有一个理发师和N张可供顾客等待理发的椅子,如果没有顾客,则理发师睡觉,如果有一个顾客进入理发店发现理发师在睡觉,则把他叫醒,试用信号量设计一个协调理发师和顾客的程序。
二 PV操作伪代码C语言的伪代码实现:int waiting=0 ;//等候理发的顾客数int chairs=n;//为顾客准备的椅子数semaphore customers=0, barbers=0,mutex=1;barber() {while(TRUE); //理完一人,还有顾客吗?P(cutomers); //若无顾客,理发师睡眠P(mutex); //进程互斥waiting -= 1;//等候顾客数少一个V(barbers); //理发师去为一个顾客理发V(mutex); //开放临界区cut-hair(); //正在理发}customer() {P(mutex); //进程互斥if(waiting) {waiting += 1; // 等候顾客数加1V(customers); //必要的话唤醒理发师V(mutex); //开放临界区P(barbers); //无理发师, 顾客坐着养神get-haircut( ); //一个顾客坐下等理/}else V(mutex); //人满了,离开}三程序流程图顾客模块:理发师模块:四源程序的实现因为本人对C++的多线程库函数不了解,于是使用JAVA实现理发师问题,假设有5张可供顾客理发的椅子:package com.swxy;import java.util.concurrent.Semaphore;//导入Semaphore,用于控制进程同步互斥的量。
public class BarberShop {static int cnt = 0;// 顾客static int MAX = 5;// 假设5张可供顾客理发的椅子static int busy = 0;static Semaphore mutex= new Semaphore(1);// 临界区互斥访问信号量(二进制信号量),相当于互斥锁。
计算机操作系统实验报告题目三大经典问题之生产者与消费者问题一、课程设计的性质与任务1、加深对并发协作进程同步与互斥概念的理解。
通过编写程序实现进程同步和互斥,使学生掌握有关进程(线程)同步与互斥的原理,以及解决进程(线程)同步和互斥的算法,从而进一步巩固进程(线程)同步和互斥等有关的内容。
2、掌握进程和线程的概念,进程(线程)的控制原语或系统调用的使用。
3、了解Windows2000/XP中多线程的并发执行机制,线程间的同步和互斥。
学习使用Windows2000/XP中基本的同步对象,掌握相应的API函数。
4、培养学生能够独立进行知识综合,独立开发较大程序的能力。
5、培养提高学生软件开发能力和软件的调试技术。
6、培养学生开发大型程序的方法和相互合作的精神。
7、培养学生的创新意识。
8、培养学生的算法设计和算法分析能力。
9、培养学生对问题进行文字论述和文字表达的能力。
二、课程设计的内容及其要求在Windows?XP、Windows?2000等操作系统下,使用的VC、VB、Java或C等编程语言,采用进程(线程)同步和互斥的技术编写程序实现生产者消费者问题或哲学家进餐问题或读者-写者问题或自己设计一个简单进程(线程)同步和互斥的实际问题。
要求:(1)经调试后程序能够正常运行。
(2)采用多进程或多线程方式运行,体现了进程(线程)同步互斥的关系。
(3)程序界面美观。
三、实验原理本实验要求利用PV操作实现解决生产者——消费者问题中的同步问题。
此问题描述的是一群生产者进程在生产产品并将这些产品提供给消费者进程去消费,在两者之间设置了一个具有n个缓冲区的缓冲池,生产者进程将它所生产的产品放入一个缓冲区,消费者进程可从缓冲区中取走产品去消费,但它们之间必须保持同步,即不允许消费者进程到一个空缓冲区去取产品,也不允许生产者进程向一个已装满且尚未取出的缓冲区中投放产品,并且生产者消费者互斥使用缓冲区。
四、实验原理图五、算法实现(1)有一个生产者线程ProduceThread,有1个消费者进程CustomerThread;缓冲区为shareList。
理发师问题操作系统课程设计河南城建学院《操作系统》课程设计报告课程名称: 《操作系统》课程设计设计题目: 理发师问题指导教师: 李蓓耿永军班级:学号:学生姓名:同组人员:成绩:评语:计算机科学与工程学院2014年6月19日前言现在计算机更新如此迅速的时代要学好计算机软件技术,特别是操作系统的学习,不仅要努力学好课本上的基础知识,还要经常在图书馆看些有关这方面的书籍,而更重要的是要有足够的实践经验,也要注重和同学的交流,经常尝试性的做些小的操作系统,对自己技术的提升会有很大的帮助。
同时,学习计算机操作系统技术,除了需要刻苦努力外,还需要掌握软件和操作系统的原理与设计技巧。
如何学习和掌握操作系统技术的原理与实际技巧呢?除了听课和读书之外,最好的方法恐怕就是在实践中练习。
例如,自己设计一个小型操作系统,多使用操作系统,多阅读和分析操作源代码等。
但由于我们的条件和学时有限,在理论学习过程中没有给同学们提供更多的实验机会。
本操作系统课程设计,是给同学提供一个集中实验的机会。
希望同学们通过该设计加深对所学习课程的理解。
本设计的内容是基于《操作系统原理》、《C语言程序设计》和《数据结构》等内容。
本设计是基于课程中学到的UNIX系统调用,使用操作系统环境是Red Hat Linux 9,言语开发环境是Linux的GNU C或C++。
完成本次课程设计,首先必须配置操作系统编写的所需的环境,包括虚拟机的建立和相应环境建立。
用VI编辑器编写相应得程序,以实现理发师进程的同步与互斥。
目录第一章.系统环境 ..................................................................... .. (1)1.1硬件环境 ..................................................................... . (1)1.2软件环境 ..................................................................... . (1)第二章.设计目的及要求 ..................................................................... .. (2)2.1设计目的 ..................................................................... . (2)2.2 要求 ..................................................................... .. (2)2.3 内容 ..................................................................... .. (2)第三章.总体设计 ..................................................................... .. (3)3.1程序设计组成框图 ..................................................................... (3)3.2 主函数流程图 ..................................................................... . (4)3.3理发师进程流程图 ..................................................................... (5)3.4 顾客进程流程图 ..................................................................... (5)3.5函数调用 ..................................................................... . (6)第四章.详细设计 ..................................................................... .. (7)4.1概要设计 ..................................................................... . (7)4.1.1 数据结构 ..................................................................... .. (7)4.1.2 多线程编译原理 ..................................................................... .. (7)4.1.3 创建线程 ..................................................................... .. (7)4.1.4 信号量 ..................................................................... (8)4.2 头文件声明 ..................................................................... .. (8)4.3函数定义 ..................................................................... . (9)4.4 变量定义 ..................................................................... (9)4.5函数实现 ..................................................................... . (9)第五章.调试与测试 ..................................................................... .. (11)5.1调试方法 ..................................................................... .. (11)5.2结果分析 ..................................................................... ..................................................... 13 第六章.设计中遇到的问题及解决方法 ..................................................................... (14)6.1出现的问题 ..................................................................... . (14)6.2解决方法 ..................................................................... ..................................................... 14 第七章.源程序清单和执行结果 ..................................................................... (16)7.1源程序清单 ..................................................................... . (16)7.2程序执行结果 ..................................................................... ............................................. 19 第八章.心得体会 ..................................................................... (20)第九章.参考文献 ..................................................................... (21)1 《操作系统》课程设计第一章.系统环境1.1硬件环境内存1GB,处理器1,硬盘(SCSI)50GB,网络适配器NAT。
设计思想的说明:打瞌睡的理发师问题是一种同步问题的抽象描述。
计算机系统中的每个进程都可以消费或生产某类资源,当系统中某一进程使用某一资源时,可以看作是消耗,且该进程称为消费者。
而当某个进程释放资源时,则它就相当一个生产者。
因此此题可看作是n个生产者和1个消费者问题。
顾客作为生产者,每到来一个就使计数器count增加1,以便让理发师理发(相当于消费)至最后一个顾客(相当于产品)。
并且,第1个到来的顾客应负责唤醒理发师;如果不是第1个到达的顾客,则在有空椅子的情况下坐下等待,否则离开理发店(该消息可由计数器count获得),所以可以通过一个有界缓冲区把理发师和顾客联系起来通过对信号进行P、V操作来实现有关问题和相关描述。
源程序文件:#include<windows.h>#include<stdio.h>#include<iostream>#include<process.h>#include<conio.h>#include<ctime>using namespace std;#define CHAIRS 3 //椅子的个数#define BARBERS 1 //理发师的个数#define CUSTOMESTOCOME 7 //将要来的顾客的数目typedef HANDLE semaphore;static int count=0; //记录理发店顾客的总数,初始化为0int leaved=0; //记录理发店顾客的总数,初始化为0int waiting=0;time_t endtime; //关闭营业的时间//coustomers初始化为0,最大顾客数为3semaphore customers=CreateSemaphore(NULL,0,CHAIRS,TEXT("customers")); //barbers的数量初始化为1,假设一共有1个barbersemaphorebarbers=CreateSemaphore(NULL,BARBERS,BARBERS,TEXT("barbers"));//建立互斥变量,用于保护共享资源HANDLE mutex=CreateMutex(NULL,FALSE,TEXT("mutex"));DWORD WINAPI barber(LPVOID lparameter);DWORD WINAPI customer(LPVOID lparameter);//理发师理发void cutHair();//顾客坐到椅子上等待void getChair();//等待顾客到来void wait();//顾客离开void customerLeave();//顾客进入void customerEnter();void up(HANDLE hHandle){//对指定信号量增加指定的值ReleaseSemaphore(hHandle,1,NULL);//恢复线程ResumeThread(hHandle);}void upMutex(HANDLE hMutex){//释放线程拥有的互斥体ReleaseMutex(hMutex);}void down(HANDLE hHandle){ //DOWN operation//线程挂起,等待信号WaitForSingleObject(hHandle,INFINITE);}int main(){//结束时间endtime=time(0)+20000;//创建理发师线程HANDLE barberThread=CreateThread(NULL,0,barber,NULL,0,NULL);HANDLE customerThread;//产生10个客户进程,每两个进程之间间隔一个随见时间1000~1050 while(count<CUSTOMESTOCOME){//创建客户进程customerThread=CreateThread(NULL,0,customer,NULL,0,NULL);srand(unsigned(time(0)));int time=rand()%1000+50;Sleep(time);}//释放资源CloseHandle(barberThread);CloseHandle(customerThread);CloseHandle(barbers);CloseHandle(customers);CloseHandle(mutex);cout<<"离开的顾客总数为:"<<leaved<<endl;return 0;}DWORD WINAPI barber(LPVOID lparameter) {while(time(0)<endtime){//没有客户,则进入睡眠状态down(customers);//临界区操作down(mutex);waiting=waiting-1;upMutex(mutex);//开始理发cutHair();//理发结束,理发师信号量加1up(barbers);}return 0;}DWORD WINAPI customer(LPVOID lparameter){ //客户到来customerEnter();//临界区操作down(mutex);cout<<"等̨¨待äy的Ì?顾?客¨ª数ºy: "<<waiting<<endl;cout<<"空?椅°?子Á¨®数ºy: "<<CHAIRS-waiting<<endl;if(waiting<CHAIRS){ //如果有空椅子,客户等待,否则离开if(waiting!=0){//等待顾客到来wait();}waiting=waiting+1;//客户信号量加1up(customers);upMutex(mutex);//离开临界区//理发师进程等待唤醒down(barbers);//顾客坐下来等待getChair();}else{//释放互斥锁upMutex(mutex);//顾客离开customerLeave();}return 0;}void cutHair(){static int served=0;served++;cout<<理发师帮第"<<served<<"位被服务的顾客理发"<<endl;Sleep(1000);cout<<"第"<<served<<"位被服务的顾客理完发"<<endl;}void getChair(){Sleep(1050);}void customerEnter(){count++;SYSTEMTIME sys;GetLocalTime( &sys );cout<<endl<<"第"<<count<<"位顾客进来"<<endl;}void wait(){cout<<"有空位,第"<<count<<"位顾客就坐"<<endl;}void customerLeave(){cout<<"没有空椅子,第"<<count<<"位顾客离开 ."<<endl;leaved++;}输出截图:PS:由于我对c++中处理进程、信号的函数不熟,所以有许多参考了网上的代码。
计算机科学与技术学院操作系统实验报告学院:专业:班级:姓名:学号:日期:Email:目录实验一进程控制实验 (4)1.1实验目的 (4)1.2实验题目 (4)1.3实验步骤 (4)1.4结论分析与体会 (5)1.5附录:本实验全部程序源代码及注释 (5)1.5.1Pctl.c (5)1.5.2pctl.h (9)1.5.3makefile (10)实验三进程调度算法实验 (10)3.1实验目的 (10)3.2实验题目 (11)3.3实验步骤 (11)3.4结论分析与体会 (12)3.5附录:本实验全部程序源代码及注释 (12)3.5.1Psched.c (12)3.5.2Psched.h (14)3.5.3Makefile (16)实验四进程同步实验 (16)4.1实验目的 (16)4.2实验题目 (16)4.3实验步骤 (17)4.4结论分析与体会 (24)4.5附录:本实验全部程序源代码及注释 (24)4.5.1Ipc.c (24)4.5.2Ipc.h (32)4.5.3Consumer (35)4.5.4Producer (41)4.5.5makefile (50)实验七内存页面置换算法实验 (51)7.1实验目的 (51)7.2实验题目 (51)7.3实验步骤 (52)7.4附录:本实验全部程序源代码及注释 (55)7.4.1Vmrp.h (55) (57)7.5.3makefile (73)实验八磁盘移臂调度算法实验 (74)7.2实验目的 (74)8.2实验题目 (74)8.3实验步骤 (75)8.4附录:本实验全部程序源代码及注释 (76)8.4.1Dask.h (76) (78)8.4.3Makefile (94)实验一进程控制实验1.1 实验目的加深对于进程并发执行概念的理解。
实践并发进程的创建和控制方法。
观察和体验进程的动态特性。
进一步理解进程生命期期间创建、变换、撤销状态变换的过程。
课程实验报告题目计算机操作系统理发师问题姓名潘 *学号 2013 ***年级专业2013级*指导教师彭 * 华201*年1*月 30 日一题目假设有个理发店,只有一个理发师和N张可供顾客等待理发的椅子,如果没有顾客,则理发师睡觉,如果有一个顾客进入理发店发现理发师在睡觉,则把他叫醒,试用信号量设计一个协调理发师和顾客的程序。
二 PV操作伪代码C语言的伪代码实现:int waiting=0 ;//等候理发的顾客数int chairs=n;//为顾客准备的椅子数semaphore customers=0, barbers=0,mutex=1;barber() {while(TRUE); //理完一人,还有顾客吗?P(cutomers); //若无顾客,理发师睡眠P(mutex); //进程互斥waiting -= 1;//等候顾客数少一个V(barbers); //理发师去为一个顾客理发V(mutex); //开放临界区cut-hair(); //正在理发}customer() {P(mutex); //进程互斥if(waiting) {waiting += 1; // 等候顾客数加1V(customers); //必要的话唤醒理发师V(mutex); //开放临界区P(barbers); //无理发师, 顾客坐着养神get-haircut( ); //一个顾客坐下等理/}else V(mutex); //人满了,离开}三程序流程图顾客模块:理发师模块:四源程序的实现因为本人对C++的多线程库函数不了解,于是使用JAVA实现理发师问题,假设有5张可供顾客理发的椅子:package com.swxy;import java.util.concurrent.Semaphore;//导入Semaphore,用于控制进程同步互斥的量。
public class BarberShop {static int cnt = 0;// 顾客static int MAX = 5;// 假设5张可供顾客理发的椅子static int busy = 0;static Semaphore mutex= new Semaphore(1);// 临界区互斥访问信号量(二进制信号量),相当于互斥锁。
计算机科学与技术学院操作系统实验报告实验题目:理发店问题理发店问题:假设理发店的理发室中有3个理发椅子和3个理发师,有一个可容纳4个顾客坐等理发的沙发。
此外还有一间等候室,可容纳13位顾客等候进入理发室。
顾客如果发现理发店中顾客已满(超过20人),就不进入理发店。
在理发店内,理发师一旦有空就为坐在沙发上等待时间最长的顾客理发,同时空出的沙发让在等候室中等待时间最长的的顾客就坐。
顾客理完发后,可向任何一位理发师付款。
但理发店只有一本现金登记册,在任一时刻只能记录一个顾客的付款。
理发师在没有顾客的时候就坐在理发椅子上睡眠。
理发师的时间就用在理发、收款、睡眠上。
请利用linux系统提供的IPC进程通信机制实验并实现理发店问题的一个解法。
实验目的:进一步研究和实践操作系统中关于并发进程同步与互斥操作的一些经典问题的解法,加深对于非对称性互斥问题有关概念的理解。
观察和体验非对称性互斥问题的并发控制方法。
进一步了解Linux系统中IPC进程同步工具的用法,训练解决对该类问题的实际编程、调试和分析问题的能力。
硬件环境:Inter(R)Core(TM)*******************内存:4GB 硬盘:500G软件环境:XUbuntu-Linux 操作系统Gnome 桌面 2.18.3BASH_VERSION='3.2.33(1)-releasegcc version 4.1.2gedit 2.18.2OpenOffice 2.3实验步骤:1、问题分析:为了解决本实验的同步问题,采用共享内存,信号量,消息队列三种IPC 同步对象处理。
客户程序思想:每一个客户把自己的请求当做一条消息发送到相应的消息队列中去,并通过阻塞等待接收消息的方式来等待理发师最终帮自己理发。
每一个客户先判断sofa 是不是坐满了,如果没有就坐在沙发上等,否者就判断waitroom 是不是坐满了,如果没有,就坐在waitroom 等,只要有一个坐在sofa的客户离开sofa 理发,理发师就会到waitroom 找最先来的客户,让他进入sofa 等待。
理发师程序思想:理发师查看sofa 上有没有人,没有就睡3 秒,然后再一次看有没有人,如果有人,就到沙发请最先来的客户来理发。
账本互斥的实现:Semaphore mutex=1 ;Sofa 队列的长度和wait 队列的长度的实现:在顾客进程中设置两个变量sofa_count,wait_count,分别保存沙发和等候室的顾客数。
2、算法设计说明如下:该解法利用消息队列的每条消息代表每个顾客,将进入等候室的顾客组织到一个队列,将坐入沙发的顾客组织到另一个队列。
理发师从沙发队列请出顾客,空出的沙发位置再从等候室请入顾客进入沙发队列。
三个理发师进程使用相同的程序段上下文,所有顾客使用同一个程序段上下文。
这样可避免产生太多进程,以便节省系统资源。
理发师程序(Barber){建立一个互斥帐本信号量:s_account,初值=1;建立一个同步顾客信号量:s_customer,初值=0;建立沙发消息队列:q_sofa;建立等候室消息队列:q_wait;建立3个理发师进程:b1_pid, b2_pid, b3_pid;每个理发师进程作:while(1){以阻塞方式从沙发队列接收一条消息,如果有消息,则消息出沙发队列(模拟一顾客理发);唤醒顾客进程(让下一顾客坐入沙发)。
用进程休眠一个随机时间模拟理发过程。
理完发,使用帐本信号量记账。
互斥的获取账本记账唤醒用账本理发师者否则没有消息(沙发上无顾客)则理发师进程在沙发队列上睡眠;当沙发队列有消息时被唤醒(有顾客坐入沙发)。
}}顾客程序(customer){while(1){取沙发队列消息数(查沙发上顾客数) ;如果消息数小于4(沙发没座满)以非阻塞方式从等候室队列接收一条消息(查等候室有顾客否),如果有消息将接收到的消息发送到沙发队列(等候室顾客坐入沙发);否则发送一条消息到沙发队列(新来的顾客直接坐入沙发);否则(沙发坐满)取等候室队列消息数(查等候室顾客数) ;如果消息数小于13发送一条消息到等候室队列(等候室没满,新顾客进等候室);否则在顾客同步信号量上睡眠(等候室满暂不接待新顾客);用进程休眠一个随机时间模拟顾客到达的时间间隔。
}}3、开发调试过程:在shell命令行下运行$ make barber customergcc -g -c barber.c ipc.cgcc barber.o ipc.o -o barbergcc -g -c customer.c ipc.cgcc customer.o ipc.o -o customer假设先运行理发师程序:$ ./barber2726号理发师睡眠2728号理发师睡眠2727号理发师睡眠运行$./customer1号新顾客坐入沙发2号新顾客坐入沙发3号新顾客坐入沙发4号新顾客坐入沙发5号新顾客坐入沙发6号新顾客坐入沙发7号新顾客坐入沙发8号新顾客坐入沙发9号新顾客坐入沙发10号新顾客坐入沙发11号新顾客坐入沙发12号新顾客坐入沙发沙发坐满13号顾客在等候室等候13号顾客从等候室坐入沙发沙发坐满14号顾客在等候室等候14号顾客从等候室坐入沙发沙发坐满15号顾客在等候室等候15号顾客从等候室坐入沙发沙发坐满16号顾客在等候室等候16号顾客从等候室坐入沙发17号新顾客坐入沙发沙发坐满18号顾客在等候室等候18号顾客从等候室坐入沙发沙发坐满19号顾客在等候室等候19号顾客从等候室坐入沙发沙发坐满20号顾客在等候室等候20号顾客从等候室坐入沙发沙发坐满21号顾客在等候室等候21号顾客从等候室坐入沙发......在理发师窗体理发师进程被唤醒:2726号理发师为1号顾客理发……2726号理发师收取1号顾客交费2726号理发师睡眠2728号理发师为2号顾客理发……2728号理发师收取2号顾客交费2728号理发师睡眠2727号理发师为3号顾客理发……2726号理发师为4号顾客理发……2727号理发师收取3号顾客交费2727号理发师睡眠2726号理发师收取4号顾客交费2726号理发师睡眠2728号理发师为5号顾客理发……2728号理发师收取5号顾客交费2728号理发师睡眠2727号理发师为6号顾客理发……2726号理发师为7号顾客理发……2727号理发师收取6号顾客交费2727号理发师睡眠2726号理发师收取7号顾客交费2726号理发师睡眠2728号理发师为8号顾客理发……2728号理发师收取8号顾客交费......反之,如果先运行顾客程序:$ ./customer1号新顾客坐入沙发2号新顾客坐入沙发3号新顾客坐入沙发4号新顾客坐入沙发沙发坐满5号顾客在等候室等候沙发坐满6号顾客在等候室等候沙发坐满7号顾客在等候室等候沙发坐满8号顾客在等候室等候沙发坐满9号顾客在等候室等候沙发坐满10号顾客在等候室等候沙发坐满11号顾客在等候室等候沙发坐满12号顾客在等候室等候沙发坐满13号顾客在等候室等候沙发坐满14号顾客在等候室等候沙发坐满15号顾客在等候室等候沙发坐满16号顾客在等候室等候沙发坐满17号顾客在等候室等候等候室满18号顾客没有进入理发店当18号顾客到达时理发店20个位置已满,顾客进程阻塞(假设理发师进程没运行表示三个理发师正坐在3个理发椅上睡觉) 。
再运行理发师程序:$ ./barber运行截图如下:附件:4.7.分析与感悟:首先运行顾客程序的话,顾客程序首先向沙发队列发送消息,然后向等候室队列发送消息,当两个队列都满了之后,该进程会暂停,及停止在顾客同步信号量上。
而随着理发师程序的开始运行,理发师进程会唤醒顾客进程,及在顾客同步信号量上进行up操作,并且从消息队列中接受消息。
反之,若理发师程序先运行,则三个理发师由于无法从沙发队列上接收到消息,而且由于是阻塞式接受,就会阻塞在这个消息队列上,只有当顾客程序运行时,向沙发队列发送消息后理发师进程才会继续。
通过编写这个实验,是我更加熟练了信号量的使用,明白了消息队列的使用方法,进一步了解了Linux系统中IPC进程同步工具的用法。
附件:Ipc.c#include "ipc.h"int get_ipc_id(char *proc_file,key_t key){FILE *pf;int i,j;char line[BUFSZ],colum[BUFSZ];if((pf = fopen(proc_file,"r")) == NULL){perror("Proc file not open");exit(EXIT_FAILURE);}fgets(line, BUFSZ, pf);while(!feof(pf)){i = j = 0;fgets(line, BUFSZ,pf);while(line[i] == ' ') i++;while(line[i] !=' ') colum[j++] = line[i++]; colum[j] = '\0';if(atoi(colum) != key) continue;j=0;while(line[i] == ' ') i++;while(line[i] !=' ') colum[j++] = line[i++]; colum[j] = '\0';i = atoi(colum);fclose(pf);return i;}fclose(pf);return -1;}int down(int sem_id){struct sembuf buf;buf.sem_op = -1;buf.sem_num = 0;buf.sem_flg = SEM_UNDO;if((semop(sem_id,&buf,1)) <0) { perror("down error ");exit(EXIT_FAILURE);}return EXIT_SUCCESS;}int up(int sem_id){struct sembuf buf;buf.sem_op = 1;buf.sem_num = 0;buf.sem_flg = SEM_UNDO;if((semop(sem_id,&buf,1)) <0) { perror("up error ");exit(EXIT_FAILURE);}return EXIT_SUCCESS;}int set_sem(key_t sem_key,int sem_val,int sem_flg){int sem_id;Sem_uns sem_arg;//测试由sem_key 标识的信号灯数组是否已经建立if((sem_id = get_ipc_id("/proc/sysvipc/sem",sem_key)) < 0 ) {//semget 新建一个信号灯,其标号返回到sem_idif((sem_id = semget(sem_key,1,sem_flg)) < 0){perror("semaphore create error");exit(EXIT_FAILURE);}//设置信号灯的初值sem_arg.val = sem_val;if(semctl(sem_id,0,SETV AL,sem_arg) <0){perror("semaphore set error");exit(EXIT_FAILURE);}}return sem_id;}char * set_shm(key_t shm_key,int shm_num,int shm_flg){int i,shm_id;char * shm_buf;//测试由shm_key 标识的共享内存区是否已经建立if((shm_id = get_ipc_id("/proc/sysvipc/shm",shm_key)) < 0 ) {//shmget 新建一个长度为shm_num 字节的共享内存,其标号返回到shm_idif((shm_id = shmget(shm_key,shm_num,shm_flg)) <0){perror("shareMemory set error");exit(EXIT_FAILURE);}//shmat 将由shm_id 标识的共享内存附加给指针shm_buf if((shm_buf = (char *)shmat(shm_id,0,0)) < (char *)0){perror("get shareMemory error");exit(EXIT_FAILURE);}for(i=0; i<shm_num; i++) shm_buf[i] = 0; //初始为0}//shm_key 标识的共享内存区已经建立,将由shm_id 标识的共享内存附加给指针shm_bufif((shm_buf = (char *)shmat(shm_id,0,0)) < (char *)0){perror("get shareMemory error");exit(EXIT_FAILURE);}return shm_buf;}int set_msq(key_t msq_key,int msq_flg){int msq_id;//测试由msq_key 标识的消息队列是否已经建立if((msq_id = get_ipc_id("/proc/sysvipc/msg",msq_key)) < 0 ) {//msgget 新建一个消息队列,其标号返回到msq_idif((msq_id = msgget(msq_key,msq_flg)) < 0) {perror("messageQueue set error");exit(EXIT_FAILURE);}}return msq_id;}Ipc.h:#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/ipc.h>#include <sys/shm.h>#include <sys/sem.h>#include <sys/msg.h>#define BUFSZ 256#define MAXV AL 100#define STRSIZ 8#define WRITERQUEST 1#define READERQUEST 2#define FINISHED 3//写请求标识//读请求标识//读写完成标识typedef union semuns { int val;} Sem_uns;typedef struct msgbuf { long mtype;int mid;} Msg_buf;//信号量key_t costomer_key; int costomer_sem;key_t account_key;int account_sem;int sem_val;int sem_flg;//消息队列int wait_quest_flg;key_t wait_quest_key;int wait_quest_id;int wait_respond_flg;key_t wait_respond_key;int wait_respond_id;int sofa_quest_flg;key_t sofa_quest_key;int sofa_quest_id;int sofa_respond_flg;key_t sofa_respond_key;int sofa_respond_id;int get_ipc_id(char *proc_file,key_t key);char *set_shm(key_t shm_key,int shm_num,int shm_flag); int set_msq(key_t msq_key,int msq_flag);int set_sem(key_t sem_key,int sem_val,int sem_flag);int down(int sem_id);int up(int sem_id);Barber.c:#include "ipc.h"int main(int argc,char *argv[]){// int i;int rate;Msg_buf msg_arg;//可在在命令行第一参数指定一个进程睡眠秒数,以调解进程执行速度if(argv[1] != NULL) rate = atoi(argv[1]);else rate = 3;//联系一个请求消息队列wait_quest_flg = IPC_CREAT| 0644;wait_quest_key = 101;wait_quest_id = set_msq(wait_quest_key,wait_quest_flg);//联系一个响应消息队列wait_respond_flg = IPC_CREAT| 0644;wait_respond_key = 102;wait_respond_id = set_msq(wait_respond_key,wait_respond_flg);//联系一个请求消息队列sofa_quest_flg = IPC_CREAT| 0644;sofa_quest_key = 201;sofa_quest_id = set_msq(sofa_quest_key,sofa_quest_flg);//联系一个响应消息队列sofa_respond_flg = IPC_CREAT| 0644;sofa_respond_key = 202;sofa_respond_id = set_msq(sofa_respond_key,sofa_respond_flg);//信号量使用的变量costomer_key = 301;//顾客同步信号灯键值account_key = 302;//账簿互斥信号灯键值sem_flg = IPC_CREAT | 0644;//顾客同步信号灯初值设为0sem_val = 0;//获取顾客同步信号灯,引用标识存costomer_semcostomer_sem = set_sem(costomer_key,sem_val,sem_flg);//账簿互斥信号灯初值设为1sem_val = 1;//获取消费者同步信号灯,引用标识存cons_semaccount_sem = set_sem(account_key,sem_val,sem_flg);int pid1, pid2;pid1=fork();if(pid1==0) {while(1) {// wait_quest_flg=IPC_NOW AIT;printf("%d号理发师睡眠\n", getpid());wait_quest_flg=0;if(msgrcv(sofa_quest_id, &msg_arg, sizeof(msg_arg), 0, wait_quest_flg)>=0) {msgsnd(sofa_respond_id, &msg_arg,sizeof(msg_arg), 0);printf("%d号理发师为%d号顾客理发……\n", getpid(), msg_arg.mid);sleep(rate);down(account_sem);printf("%d号理发师收取%d号顾客交费\n", getpid(), msg_arg.mid);up(account_sem);}}} else {pid2=fork();if(pid2==0) {while(1) {// wait_quest_flg=IPC_NOW AIT;printf("%d号理发师睡眠\n", getpid());wait_quest_flg=0;if(msgrcv(sofa_quest_id, &msg_arg, sizeof(msg_arg), 0, wait_quest_flg)>=0) {msgsnd(sofa_respond_id,&msg_arg,sizeof(msg_arg), 0);printf("%d号理发师为%d号顾客理发……\n", getpid(), msg_arg.mid);sleep(rate);down(account_sem);printf("%d号理发师收取%d号顾客交费\n", getpid(), msg_arg.mid);up(account_sem);} else {printf("%d号理发师睡眠\n", getpid());}}} else {while(1) {// wait_quest_flg=IPC_NOW AIT;printf("%d号理发师睡眠\n", getpid());wait_quest_flg=0;if(msgrcv(sofa_quest_id, &msg_arg, sizeof(msg_arg), 0, wait_quest_flg)>=0) {msgsnd(sofa_respond_id,&msg_arg,sizeof(msg_arg), 0);printf("%d号理发师为%d号顾客理发……\n", getpid(), msg_arg.mid);sleep(rate);down(account_sem);printf("%d号理发师收取%d号顾客交费\n", getpid(), msg_arg.mid);up(account_sem);} else {printf("%d号理发师睡眠\n", getpid());}}}}return 0;}Customer.c:#include "ipc.h"int main(int argc,char *argv[]){int rate;Msg_buf msg_arg;//可在在命令行第一参数指定一个进程睡眠秒数,以调解进程执行速度if(argv[1] != NULL) rate = atoi(argv[1]);else rate = 3;//联系一个请求消息队列wait_quest_flg = IPC_CREAT| 0644;wait_quest_key = 101;wait_quest_id = set_msq(wait_quest_key,wait_quest_flg);//联系一个响应消息队列wait_respond_flg = IPC_CREAT| 0644;wait_respond_key = 102;wait_respond_id = set_msq(wait_respond_key,wait_respond_flg);//联系一个请求消息队列sofa_quest_flg = IPC_CREAT| 0644;sofa_quest_key = 201;sofa_quest_id = set_msq(sofa_quest_key,sofa_quest_flg);//联系一个响应消息队列sofa_respond_flg = IPC_CREAT| 0644;sofa_respond_key = 202;sofa_respond_id = set_msq(sofa_respond_key,sofa_respond_flg);//信号量使用的变量costomer_key = 301;//顾客同步信号灯键值account_key = 302;//账簿互斥信号灯键值sem_flg = IPC_CREAT | 0644;//顾客同步信号灯初值设为0sem_val = 0;//获取顾客同步信号灯,引用标识存costomer_semcostomer_sem = set_sem(costomer_key,sem_val,sem_flg);//账簿互斥信号灯初值设为1sem_val = 1;//获取消费者同步信号灯,引用标识存cons_semaccount_sem = set_sem(account_key,sem_val,sem_flg);int sofa_count=0;int wait_count=0;int i=0;// int count=0;while(1) {sleep(rate);// count++;// printf("count = %d ", count);i++;// printf("i = %d ", i);msg_arg.mid = i;if(sofa_count < 4) {if(wait_count != 0) {i--;//阻塞方式接收消息msgrcv(wait_quest_id, &msg_arg, sizeof(msg_arg), 0, 0);printf("mid = %d ", msg_arg.mid);msgsnd(wait_respond_id, &msg_arg,sizeof(msg_arg), 0);printf("%d号顾客从等候室坐入沙发\n", msg_arg.mid);// up(costomer_sem);} else {printf("%d号新顾客坐入沙发\n", i);}sofa_quest_flg=IPC_NOW AIT;if(msgsnd(sofa_quest_id, &msg_arg, sizeof(msg_arg), sofa_quest_flg) >= 0){// sofa_count++;// return 0;}sofa_count++;} else if(wait_count < 13) {printf("沙发坐满,%d号顾客在等候室等候……\n", i);wait_quest_flg = IPC_NOWAIT;msgsnd(wait_quest_id, &msg_arg, sizeof(msg_arg), wait_quest_flg);wait_count++;} else {printf("等候室满,%d顾客没有进入理发店\n", i);// down(costomer_sem);msgrcv(sofa_respond_id, &msg_arg, sizeof(msg_arg), 0, 0);sofa_count--;i--;}sofa_quest_flg=IPC_NOW AIT;if(msgrcv(sofa_respond_id, &msg_arg, sizeof(msg_arg), 0, sofa_quest_flg)>=0){sofa_count--;}wait_quest_flg = IPC_NOW AIT;if(msgrcv(wait_respond_id, &msg_arg, sizeof(msg_arg), 0, wait_quest_flg)>=0) {wait_count--;}}return 0;}。