《山东大学操作系统实验四(共16页).docx》由会员分享,可在线阅读,更多相关《山东大学操作系统实验四(共16页).docx(16页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、精选优质文档-倾情为你奉上软件学院操作系统实验报告实验题目:实验四、进程同步实验学号:4日期:2013年05月10日班级:5班 姓名:韩俊晓Email:实验目的:加深对并发协作进程同步与互斥概念的理解,观察和体验并发进程同步与互斥操作的效果,分析与研究经典进程同步与互斥问题的实际解决方案。了解Linux系统中IPC进程同步工具的用法,练习并发协作进程的同步与互斥操作的编程与调试技术。实验要求:抽烟者问题。假设一个系统中有三个抽烟者进程,每个抽烟者不断地卷烟并抽烟。抽烟者卷起并抽掉一颗烟需要有三种材料:烟草、纸和胶水。一个抽烟者有烟草,一个有纸,另一个有胶水。系统中还有两个供应者进程,它们无限地
2、供应所有三种材料,但每次仅轮流提供三种材料中的两种。得到缺失的两种材料的抽烟者在卷起并抽掉一颗烟后会发信号通知供应者,让它继续提供另外的两种材料。这一过程重复进行。请用以上介绍的IPC同步机制编程,实现该问题要求的功能。硬件环境:实验室计算机软件环境:Ubuntu08.4Linux操作系统BASH_VERSION=3.2.33(1)-releasegcc version 4.1.2gedit 2.18.2OpenOffice 2.3 实验步骤:实验思路:(1)对于生产者进程可以创建一个子进程,这样父子进程就构成了两个生产者,同时产生随机数来控制往共享内存中写的内容;(2)对于消费者进程,创建两
3、个子进程,与父进程一起就构成了三个消费者进程,然后从共享内存中读取数据即可。1.实验说明:在linux系统中可以利用进程间通信(interprocess communication )IPC中的3个对象:共享内存、信号灯数组、消息队列,来解决协作并发进程间的同步与互斥的问题。1)共享内存是OS内核为并发进程间交换数据而提供的一块内存区(段)。如果段的权限设置恰当,每个要访问该段内存的进程都可以把它映射到自己私有的地址空间中。如果一进程更新了段中数据,那么其他进程立即会看到这一更新。进程创建的段也可由另一进程读写。linux中可用命令ipcs -m 观察共享内存情况。$ ipcs -m-Shar
4、edMemory Segments -key shmid owner perms bytes nattch status0x student 600 2 dest0x student 600 2 dest0x student 600 2 destkey共享内存关键值shmid共享内存标识owner共享内存所由者(本例为student)perm共享内存使用权限(本例为student可读可写)byte共享内存字节数nattch共享内存使用计数status共享内存状态上例说明系统当前已由student建立了一些共享内存,每个都有两个进程在共享。2)信号灯数组是OS内核控制并发进程间共享资源的一种进程
5、同步与互斥机制。linux中可用命令ipcs -s 观察信号灯数组的情况。$ ipcs -s-SemaphoreArrays -key semid owner perms nsems apache 600 10x4d00f259 beagleind 600 80x student 644 1semid信号灯的标识号nsems信号灯的个数其他字段意义同以上共享内存所述。上例说明当前系统中已经建立多个信号灯。其中最后一个标号为是由student建立的,它的使用权限为644,信号灯数组中信号灯个数为1个。3)消息队列是OS内核控制并发进程间共享资源的另一种进程同步机制。linux中可用命令ipcs
6、-q 观察消息队列的情况。$ipcs -q -Message Queues -key msqid owner perms used-bytes messages0xc8 0 root 644 8 1msgmid消息队列的标识号used-bytes 消息的字节长度messages 消息队列中的消息条数其他字段意义与以上两种机制所述相同。上例说明当前系统中有一条建立消息队列,标号为0,为root所建立,使用权限为644,每条消息8个字节,现有一条消息。4) 在权限允许的情况下您可以使用ipcrm命令删除系统当前存在的IPC对象中的任一个对象。ipcrm -m 21482删除标号为21482的共享内
7、存。ipcrm -s 32673删除标号为32673的信号灯数组。ipcrm -q 18465删除标号为18465的消息队列。5) 在linux的proc文件系统中有3个虚拟文件动态记录了由以上ipcs命令显示的当前IPC对象的信息,它们分别是:/proc/sysvipc/shm共享内存/proc/sysvipc/sem信号量/proc/sysvipc/msg消息队列我们可以利用它们在程序执行时获取有关IPC对象的当前信息。6) IPC对象有关的系统调用函数原型都声明在以下的头文件中:#include #include 创建一段共享内存系统调用语法:#include int shmget(ke
8、y_t key,int size,int flags); key 共享内存的键值,可以为IPC_PRIVATE,也可以用整数指定一个size 共享内存字节长度flags 共享内存权限位。shmget调用成功后,如果key用新整数指定,且flags中设置了IPC_CREAT位,则返回一个新建立的共享内存段标识符。如果指定的key已存在则返回与key关联的标识符。不成功返回-1令一段共享内存附加到调用进程中的系统调用语法:#include char *shmat(int shmid, char *shmaddr,int flags) shmid 由shmget创建的共享内存的标识符shmaddr
9、总为0,表示用调用者指定的指针指向共享段flags 共享内存权限位shmat调用成功后返回附加的共享内存首地址令一段共享内存从到调用进程中分离出去的系统调用语法:#include int shmdt(char *shmadr);shmadr进程中指向附加共享内存的指针shmdt调用成功将递减附加计数,当计数为0,将删除共享内存。调用不成功返回-1。创建一个信号灯数组的系统调用有语法:#include int semget(key_t key,int nsems, int flags);key 信号灯数组的键值,可以为IPC_PRIVATE,也可以用整数指定一个nsems 信号灯数组中信号灯的个
10、数flags 信号灯数组权限位。如果key用整数指定,应设置IPC_CREAT位。semget调用成功,如果key用新整数指定,且flags中设置了IPC_CREAT位,则返回一个新建立的信号等数组标识符。如果指定的整数key已存在则返回与key关联的标识符。不成功返回-1操作信号灯数组的系统调用语法:#include int semop(int semid,struct sembuf *semop, unsigned nops);semid 由semget创建的信号灯数组的标识符semop 指向sembuf数据结构的指针nops 信号灯数组元素的个数。semop调用成功返回0,不成功返回-1
11、。控制信号灯数组的系统调用语法:#include int semctl(int semid,int semnum,int cmd, union semun arg);semid 由semget创建的信号灯数组的标识符semnum 该信号灯数组中的第几个信号灯cmd 对信号灯发出的控制命令。例如:GETVAL 返回当前信号灯状态SETVAL 设置信号灯状态IPC_RMID删除标号为semid的信号灯arg 保存信号灯状态的联合体,信号灯的值是其中一个基本成员union semun int val; /* value for SETVAL */.; semctl 执行不成功返回-1,否则返回指定的
12、cmd的值。创建消息队列的系统调用语法:#includeint msgget(key_t key,int flags)key 消息队列的键值,可以为IPC_PRIVATE,也可以用整数指定一个flags 消息队列权限位。msgget调用成功,如果key用新整数指定,且flags中设置了IPC_CREAT位,则返回一个新建立的消息队列标识符。如果指定的整数key已存在则返回与key关联的标识符。成功返回-1。追加一条新消息到消息队列的系统调用语法:#include int msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgfl
13、g);msqid由消息队列的标识符msgp消息缓冲区指针。消息缓冲区结构为:struct msgbuf long mtype;/* 消息类型,必须大于*/char mtext1; /* 消息数据,长度应于msgsz声明的一致*/msgsz消息数据的长度msgflg为表示阻塞方式,设置IPC_NOWAIT表示非阻塞方式msgsnd调用成功返回0,不成功返回-1。从到消息队列中读出一条新消息的系统调用语法:#include int msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz,long msgtype, int msgflg);msqid由
14、消息队列的标识符msgp消息缓冲区指针。消息缓冲区结构为:struct msgbuf long mtype; /* 消息类型,必须大于*/char mtext1; /* 消息数据,长度应于msgsz声明的一致*/msgsz消息数据的长度msgtype决定从队列中返回哪条消息:=0返回消息队列中第一条消息0返回消息队列中等于mtype类型的第一条消息。0返回mtype=type绝对值最小值的第一条消息。msgflg为表示阻塞方式,设置IPC_NOWAIT表示非阻塞方式msgrcv调用成功返回0,不成功返回-1。删除消息队列的系统调用语法:#include int msgctl(int msqid
15、, int cmd, struct msqid_ds *buf);msqid由消息队列的标识符cmd控制命令。常用的有:IPC_RMID删除msgid标识的消息队列IPC_STAT为非破坏性读,从队列中读出一个msgid_ds结构填充缓冲bufIPC_SET改变队列的UID,GID,访问模式和最大字节数。msgctl调用成功返回0,不成功返回-1。3.调试过程:1) 建立以下名为ipc.h的C语言头文件:#include #include #include #include #include #include #include #define BUFSZ 256int get_ipc_id(c
16、har *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);int set_sem(key_t sem_key,int sem_val,int sem_flag);int P(int sem_id);int V(int sem_id);typedef union semunsint val;Sem_uns;typedef struct msgbuflong mtype;char mtext1;Msg_buf;key_t buf
17、f_key;int buff_num;char *buff_ptr;key_t pput_key;int pput_num;int *pput_ptr;key_t cget_key;int cget_num;int *cget_ptr;key_t prod_key;key_t pmtx_key;int prod_sem;int pmtx_sem;key_t cmtx_key;key_t cPG_key;key_t cTG_key;key_t cTP_key;int cPG_sem;int cTP_sem;int cTG_sem;int cmtx_sem;int sem_val;int sem_
18、flg;int shm_flg;int rate;2)建立ipc.c、producer.c和consumer.c程序。其中实验思想为假设T,P,G分别为吸烟必备材料(T=烟草,P=纸,G=胶水)。供应商每次随机供应(生产)卷烟材料中的两种:T&P,P&G,G&T。每种材料各放在一个容器中。要求两种材料来自于一个供应者在一次供应时提供的。例如:具有烟草T的吸烟者要获得P&G,P&G是一个供应者在某一次供应时提供的,不允许从一个供应者提供的T&P和另一个供应者提供的G&T中各取P和G进行卷烟。即要求原料成对放入,再按放入时的组合成对的取出,每对材料视为一件产品。容器对缓冲区利用的约束:当供应者随机
19、放入三种产品时,从缓冲区申请位置,然后放入。由于放入的产品具有随机性,所以产品在缓冲区的位置也就具有随机性,因此对卷烟者而言,就算知道缓冲区有自己想要的产品,但不知道从缓冲区的哪个位置去获得产品。所以要对缓冲区三种产品的存放位置进行约束。最简单的模拟解决方案:申请一个三个字节共享内存缓冲区,用每个字节放一个材料,缓冲区首单元为放烟草T的容器,第二字节为放纸张P的容器,第三字节为放胶水G的容器。每次同时操作3个容器中的两对组合。供应者(生产者)进程:用同一个程序产生两个供应商进程,它们使用同一段程序上下文,每次放产品到容器时,必须保证吸烟者拿走旧材料后再放新材料,因此这就需要3个放产品的同步信号
20、量对其进行约束;并且两供应商必须互斥的向容器中放入材料。因此这就需要3个放产品的互斥信号量对其进行约束。吸烟者(消费者)进程:用同一个程序产生3个吸烟者进程,分别有各自的程序上下文,各为拥有烟草T材料需要材料P&G的吸烟者,拥有纸张P材料需要材料G&T的吸烟者,拥有胶水G材料需要材料T&P的吸烟者。吸烟者欲卷烟首先要获得另外两种所需材料。当容器中没有自己恰好需要的材料时,吸烟者就要等待。并且3个吸烟者必须互斥的从容器中获取材料。因此这就需要3个取产品的同步信号量,3个取产品的互斥信号量对其进行约束。3)建立以下项目管理文件Makefilehdrs = ipc.hopts = -g -cc_sr
21、c = consumer.c ipc.cc_obj = consumer.o ipc.op_src = producer.c ipc.c p_obj = producer.o ipc.oall:producer consumerconsumer:$(c_obj)gcc $(c_obj) -o consumer consumer.o:$(c_src) $(hdrs)gcc $(opts) $(c_src) producer:$(p_obj)gcc $(p_obj) -o producer producer.o:$(p_src) $(hdrs)gcc $(opts) $(p_src) clean:
22、rm consumer producer *.o4)输入make命令编译连接生成可执行的程序$ gmakegcc -g -c producer.c ipc.cgcc producer.o ipc.o -o producergcc -g -c consumer.c ipc.cgcc consumer.o ipc.o -o consumer 5) 执行程序先执行producer.c再执行consumer.c,其结果分别显示如下:Producer.c: 实验总结:1. 实验的过程中在编写代码的时候要仔细认真,定义变量的时候要看明白变量的作用范围2. 实验时实验的步骤要记清楚,这样在执行实验的时候不会出差错3. 要善于将之前学过的知识用在后面的学习中,比如进程的创建这里就可以用到4. 学会分析题意,转化为可实现代码5. 对于编译过程中出现的错误,要有耐心去解决专心-专注-专业