2022年操作系统课程设计方案信号机制实验.docx
写在前面: 这是 操作系统课程设计试验报告( 信号机制试验),前半部分是试验手册上的内容(老师发的),后面有该试验的试验报告,这个是我自己做的,不是网上搜来的, 肯定原创 ,现在免费共享到文库上,目的是为了沟通和共享;以后会边做边共享;虽然试验报告已经被老师审核通过,但假如仍有不对的地方,请斧正;试验手册内容:一 信号机制试验试验目的1、明白什么是信号2、熟识 LINUX 系统中进程之间软中断通信的基本原理试验内容1、编写程序:用 fork 创建两个子进程,再用系统调用signal让父进程捕获键盘上来的中断信号(即按 c 键);捕获到中断信号后,父进程用系统调用kill 向两个子进程发出信号,子进程捕获到信号后分别输出以下信息后终止:Child process1 is killed by parent.Child process2 is killed by parent.父进程等待两个子进程终止后,输出如下的信息后终止:Parent process is killed.2、分析利用软中断通信实现进程同步的机理试验指导一、信号1、信号的基本概念每个信号都对应一个正整数常量 称为 signalnumber,即信号编号;定义在系统头文件 <signal.h>中,代表同一用户的诸进程之间传送事先商定的信息的类型,用于通知某进程发生了某反常大事;每个进程在运行时,都要通过信号机制来检查是否有信号到达;如有,便中断正在执行的程序,转向与该信号相对应的处理程序,以完成对该大事的处理;处理终止后再返回到原先的断点连续执行;实质上,信号机制是对中断机制的一种模拟,故在早期的UNIX版本中又把它称为软中断;信号与中断的相像点:(1) 采纳了相同的异步通信方式;(2) 当检测出有信号或中断恳求时,都暂停正在执行的程序而转去执行相应的处理程序;(3) 都在处理完毕后返回到原先的断点;(4) 对信号或中断都可进行屏蔽;信号与中断的区分:(1) 中断有优先级,而信号没有优先级,全部的信号都是公平的;(2) 信号处理程序是在用户态下运行的,而中断处理程序是在核心态下运行;(3) 中断响应是准时的,而信号响应通常都有较大的时间推迟;信号机制具有以下三方面的功能:(1) 发送信号;发送信号的程序用系统调用kill 实现;(2) 预置对信号的处理方式;接收信号的程序用signal 来实现对处理方式的预置;(3) 收受信号的进程按事先的规定完成对相应大事的处理;2、信号的发送信号的发送,是指由发送进程把信号送到指定进程的信号域的某一位上;假如目标进程正在一个可被中断的优先级上睡眠,核心便将它唤醒,发送进程就此终止;一个进程可能在其信号域中有多个位被置位,代表有多种类型的信号到达,但对于一类信号,进程却只能记住其中的某一个;进程用 kill 向一个进程或一组进程发送一个信号;3、对信号的处理当一个进程要进入或退出一个低优先级睡眠状态时,或一个进程即将从核心态返回用户态时,核心都要检查该进程是否已收到软中断;当进程处于核心态时,即使收到软中断也不予理会;只有当它返回到用户态后,才处理软中断信号; 对软中断信号的处理分三种情形进行:(1) 假如进程收到的软中断是一个已打算要忽视的信号(function=1), 进程不做任何处理便立刻返回;(2) 进程收到软中断后便退出( function=0);(3) 执行用户设置的软中断处理程序;二、所涉及的中断调用1、kill 系统调用格式参数定义int killpid,sigint pid,sig;其中, pid 是一个或一组进程的标识符,参数sig 是要发送的软中断信号;(1) pid>0 时,核心将信号发送给进程 pid;(2) pid=0 时,核心将信号发送给与发送进程同组的全部进程;(3) pid=-1 时,核心将信号发送给全部用户标识符真正等于发送进程的有效用户标识号的进程;2、signal 预置对信号的处理方式,答应调用进程掌握软中断信号;系统调用格式signalsig,function头文件为#include <signal.h>参数定义signalsig,function int sig;void *func 其中 sig 用于指定信号的类型, sig 为 0 就表示没有收到任何信号,余者如下表:值名 字说明01SIGHUP挂起( hangup)02SIGINT中断,当用户从键盘按c 键或break 键时 (输入方式 Ctrl+C )03SIGQUIT退出,当用户从键盘按quit 键时04SIGILL非法指令05SIGTRAP跟踪陷阱( trace trap),启动进程,跟踪代码的执行06SIGIOTIOT 指令07SIGEMTEMT 指令08SIGFPE浮点运算溢出09SIGKILL杀死、终止进程10SIGBUS总线错误11SIGSEGV段违例( segmentation violation ),进程试图去拜访其虚地址空间以外的位置12SIGSYS系统调用中参数错,如系统调用号非法13SIGPIPE向某个非读管道中写入数据14SIGALRM闹钟;当某进程期望在某时间后接收信号时发此信号15SIGTERM软件终止( software termination)16SIGUSR1用户自定义信号 117SIGUSR2用户自定义信号 218SIGCLD某个子进程死19SIGPWR电源故障function:在该进程中的一个函数地址,在核心返回用户态时,它以软中断信号的序号作为参数调用该函数,对除了信号 SIGKILL ,SIGTRAP 和 SIGPWR 以外的信号,核心自动地重新设置软中断信号处理程序的值为 SIG_DFL (进程终止) ,一个进程不能捕获 SIGKILL 信号;function 的说明如下:(1) function=1(即 SIG_IGN )时,进程对 sig 类信号不予理会,亦即 屏蔽了该类信号;(2) function=0即 SIG_DFL 时,缺省值,进程在收到sig 信号后应终止自己;(3) function 为非 0、非 1 类整数时, function 的值即作为信号处理程序的指针;三、参考程序#include <stdio.h> #include <signal.h> #include <unistd.h>void waiting ,stop ;int wait_mark;main int p1,p2,stdout;whilep1=fork=-1 ;/* 创建子进程 p1*/ if p1>0whilep2=fork=-1 ;/* 创建子进程 p2*/ ifp2>0wait_mark=1;signalSIGINT,stop; /* 接收到 c 信号,转 stop*/ waiting ;killp1,16 ; /* 向 p1 发软中断信号 16*/ killp2,17 ; /* 向 p2 发软中断信号 17*/ wait0 ; /*同步*/wait0 ;printf"Parent process is killed.n" ;exit0 ;elsewait_mark=1;elsesignal17,stop; /* 接收到软中断信号 17,转 stop*/ waiting ;lockfstdout,1,0;printf"Child process 2 is killed by parent.n" ;lockfstdout,0,0;exit0 ;wait_mark=1;signal16,stop;/* 接收到软中断信号 16,转 stop*/ waiting ;lockfstdout,1,0;printf"Child process 1 is killed by parent.n" ;lockfstdout,0,0;exit0; void waiting whilewait_mark.=0 ;void stop wait_mark=0;四、运行结果屏幕上无反应,按下 C 后,显示 Parent process is killed.五、分析缘由上述程序中, signal都放在一段程序的前面部位,而不是在其他接收信号处;这是由于 signal 的执行只是为进程指定信号值 16 或 17 的作用,以及安排相应的与 stop过程链接的指针;因而,signal函数必需在程序前面部分执 行;本方法通信效率低,当通信数据量较大时一般不用此法;六、摸索1、该程序段前面部分用了两个 wait0 ,它们起什么作用?2、该程序段中每个进程退出时都用了语句exit0 ,为什么?3、为何预期的结果并未显示出?4、(重点) 程序该如何修改才能得到正确结果? (试验报告中写出完整程序)5、* 不修改程序如何得到期望的输出?(给出合理的思路即可)以下为试验报告部分:试验 信号机制姓名 LeeQQ 615824191试验目的1、明白什么是信号2、熟识 LINUX 系统中进程之间软中断通信的基本原理试验内容1、编写程序:用 fork 创建两个子进程,再用系统调用signal让父进程捕获键盘上来的中断信号(即按 c 键);捕获到中断信号后,父进程用系统调用kill 向两个子进程发出信号,子进程捕获到信号后分别输出以下信息后终止:Child process1 is killed by parent.Child process2 is killed by parent.父进程等待两个子进程终止后,输出如下的信息后终止:Parent process is killed.2、分析利用软中断通信实现进程同步的机理试验步骤1. 将参考程序用 vi 编辑器录入,然后编译执行#include <stdio.h> #include <signal.h> #include <unistd.h>void waiting ,stop ;int wait_mark ;main int p1,p2,stdout;whilep1=fork=-1 ;/* 创建子进程 p1*/ if p1>0whilep2=fork=-1 ;/* 创建子进程 p2*/ ifp2>0wait_mark=1;signalSIGINT,stop; /* 接收到 c 信号,转 stop*/ waiting ;killp1,16 ;/* 向 p1 发软中断信号16*/killp2,17 ;/* 向 p2 发软中断信号17*/wait0;/* 同步*/wait0;printf"Parent process is killed.n" ;exit0 ;elsewait_mark=1;signal17,stop; /* 接收到软中断信号 17,转 stop*/ waiting ;lockfstdout,1,0;printf"Child process 2 is killed by parent.n" ;lockfstdout,0,0;exit0 ;elsewait_mark=1;signal16,stop;/* 接收到软中断信号 16,转 stop*/waiting ;lockfstdout,1,0;printf"Child process 1 is killed by parent.n" ;lockfstdout,0,0;exit0 ; void waiting whilewait_mark.=0 ;void stop wait_mark=0;2. 运行结果屏幕上无反应,按下 C 后,显示 Parent process is killed.3. 分析缘由上述程序中, signal都放在一段程序的前面部位,而不是在其他接收信号处;这是由于 signal 的执行只是为进程指定信号值 16 或 17 的作用,以及安排相应的与 stop过程链接的指针;因而, signal函数必需在程序前面部分执行;摸索1. 该程序段前面部分用了两个 wait0,它们起什么作用?该程序段前面部分用的两个wait0 是为了让父进程等待子进程终止后再终止自己,在此过程中,父进程处于挂起状态;2. 该程序段中每个进程退出时都用了语句exit0,为什么? 用 exit0 是为了让子进程自我终止,正常退出;3. 为何预期的结果并未显示出?p1、p2 都会捕获该中断信号;对于父进程,当它捕获到中断信号后就会就会转向程序中指定的函数“ stop”,当“ stop”执行完毕后,父进程被唤醒,从中断处连续运行;对于子进程,由于没有给它们指定收到中断信号后的动作,它们会在捕获到中断信号后执行默认操作,即终止自己;所以当我们发出中断信号后,父进程按估计方式正常执行,而p1、p2 就被自己终止了,从而也就不会有估计的结果了;4. 程序该如何修改才能得到正确结果?为了使程序运行得到正确的结果,可以在每个子进程程序段开头加上忽视“ C”中断信号的语句,即: signalSIGINT,SIG_IGN ;#include <stdio.h>#include <signal.h> #include <unistd.h> #include <stdlib.h> void waiting ;void stop ;int wait_mark ;main int p1,p2,stdout ;whilep1 = fork = -1 ;if p1 > 0 whilep2 = fork = -1 ;if p2 > 0 wait_mark = 1 ;signalSIGINT,stop ;waiting ;killp1,16 ;killp2,17 ;wait0 ;wait0 ;printf"Parent process is killed .n" ;exit0 ; else signalSIGINT,SIG_IGN ;wait_mark = 1 ;signal17,stop; waiting ;lockfstdout,1,0 ;printf"Child process 2 is killed by parent .n" ;lockfstdout,0,0 ;exit0 ; else signalSIGINT,SIG_IGN ;wait_mark = 1 ;signal16,stop;waiting ;lockfstdout,1,0 ;printf"Child process 1 is killed by parent .n" ;lockfstdout,0,0 ;exit0 ;void waiting whilewait_mark .= 0 ;void stop wait_mark = 0 ;4.不修改程序如何得到期望的输出?在不修改程序的情形下要输出期望的结果,可以单独向父进程发送 SIGINT 信号,这样即可防止子进程由于收到SIGINT 信号执行默认操作而自我终止,详细实现方法:(该试验中程序名为: demo2)第一让程序在后台运行,命令: ./demo2&执行该命令后,会在后台生成3 个进程,使用 ps 命令可以查看到它们的 PID (相对小的PID 应当为父进程的PID,缘由是创建时间相对早);然后向后台的父进程发送SIGINT信号,命令: killSIGINT 28664 其中 28664 为父进程的 PID详细试验结果见下图:心得与体会通过该试验,我对 UNIX/LINUX下软中断的实现原理与机制有了一个初步的熟识,可以用 kill函数和 signal 函数实现简洁的软中断程序,并且领悟到了程序中wait_mark 所起的作用;在讨论第五个摸索题时,学习了进程在前台和后台间切换和向后台进程发送信号的方法,收成许多新学问和新方法;