实验名称:
生产者与消费者问题模拟
实验目的:
通过模拟生产者消费者问题理解进程或线程之间的同步与互斥。
实验内容:
1、设计一个环形缓冲区,大小为10,生产者依次向其中写入1到20,每个缓冲区中存放一个数字,消费者从中依次读取数字。
2、相应的信号量;
3、生产者和消费者可按如下两种方式之一设计;
(1)设计成两个进程;
(2)设计成一个进程内的两个线程。
4、根据实验结果理解信号量的工作原理,进程或线程的同步\互斥关系。
实验步骤及分析:
一.管道
(一)管道定义
所谓管道,是指能够连接一个写进程和一个读进程的、并允许它们以生产者—消费者方式进行通信的一个共享文件,又称为pipe文件。由写进程从管道的写入端(句柄1)将数据写入管道,而读进程则从管道的读出端(句柄0)读出数据。
(二)所涉及的系统调用
1、pipe( )
建立一无名管道。
系统调用格式
pipe(filedes)
参数定义
int pipe(filedes);
int filedes[2];
其中,filedes[1]是写入端,filedes[0]是读出端。
该函数使用头文件如下:
#include #inlcude #include 2、read( ) 系统调用格式: read(fd,buf,nbyte) 功能:从fd所指示的文件中读出nbyte个字节的数据,并将它们送至由指针buf所指示的缓冲区中。如该文件被加锁,等待,直到锁打开为止。 参数定义: int read(fd,buf,nbyte); int fd; char *buf; unsigned nbyte; 3、write( ) 系统调用格式 read(fd,buf,nbyte) 功能:把nbyte 个字节的数据,从buf所指向的缓冲区写到由fd所指向的文件中。如文件加锁,暂停写入,直至开锁。 参数定义同read( )。 (三)参考程序 #include #include #include int pid1,pid2; main( ) { int fd[2]; char outpipe[100],inpipe[100]; pipe(fd); /*创建一个管道*/ while ((pid1=fork( ))==-1); if(pid1==0) { lockf(fd[1],1,0); /*把串放入数组outpipe中*/ sprintf(outpipe,"child 1 is using pipe!"); /*向管道写长为50字节的串*/ write(fd[1],outpipe,50); sleep(5); /*自我阻塞5秒*/ lockf(fd[1],0,0); exit(0); } else { while((pid2=fork( ))==-1); if(pid2==0) { lockf(fd[1],1,0); /*互斥*/ sprintf(outpipe,"child 2 is using pipe!"); write(fd[1],outpipe,50); sleep(5); lockf(fd[1],0,0); exit(0); } else { wait(0); /*同步*/ read(fd[0],inpipe,50);/*从管道中读长为50字节的串*/ printf("%s\\n",inpipe); wait(0); read(fd[0],inpipe,50); printf("%s\\n",inpipe); exit(0); } } } 编写过程: 运行结果: 二、信号机制 (一)信号的基本概念 每个信号都对应一个正整数常量(称为signal number,即信号编号。定义在系统头文件 (二)所涉及的中断调用 1、kill( ) 系统调用格式 int kill(pid,sig) 参数定义 int pid,sig; 其中,pid是一个或一组进程的标识符,参数sig是要发送的软中断信号。 (1)pid>0时,核心将信号发送给进程pid。 (2)pid=0时,核心将信号发送给与发送进程同组的所有进程。 (3)pid=-1时,核心将信号发送给所有用户标识符真正等于发送进程的有效用户标识号的进程。 2、signal( ) 预置对信号的处理方式,允许调用进程控制软中断信号。 系统调用格式 signal(sig,function) 头文件为 #include 参数定义 signal(sig,function) int sig; void (*func) ( ) function:在该进程中的一个函数地址,在核心返回用户态时,它以软中断信号的序号作为参数调用该函数,对除了信号SIGKILL,SIGTRAP和SIGPWR以外的信号,核心自动地重新设置软中断信号处理程序的值为SIG_DFL,一个进程不能捕获SIGKILL信号。 (三)参考程序 #include #include #include void waiting( ),stop( ); int wait_mark; main( ) { int p1, p2; int stdout1; while((p1=fork( ))==-1); /*创建子进程p1*/ if (p1>0) { while((p2=fork( ))==-1); /*创建子进程p2*/ if(p2>0) { wait_mark=1; signal(SIGINT,stop); /*接收到^c信号,转stop*/ waiting( ); kill(p1,16); /*向p1发软中断信号16*/ kill(p2,17); /*向p2发软中断信号17*/ wait(0); /*同步*/ wait(0); printf("Parent process is killed!\\n"); exit(0); } else { wait_mark=1; signal(17,stop); /*接收到软中断信号17,转stop*/ waiting( ); lockf(stdout1,1,0); printf("Child process 2 is killed by parent!\\n"); lockf(stdout1,0,0); exit(0); } } else { wait_mark=1; signal(16,stop); /*接收到软中断信号16,转stop*/ waiting( ); lockf(stdout1,1,0); printf("Child process 1 is killed by parent!\\n"); lockf(stdout1,0,0); exit(0); } } void waiting( ) { while(wait_mark!=0); } void stop( ) { wait_mark=0; } 编译过程: 运行结果: 实验总结:在实验中很多粗心造成的问题,比如指令输错字母,代码写错字母,没有注意是否需要空格等。通过课堂的理论知识学习和实验课的上机实验,让我更能理解操作系统的知识。下载本文