实验四:软中断通信***


大家好呀~~~今天是小白学操作系统系列第四篇。在开始之前,~~让我们先来摆烂

请添加图片描述

啊不,阅读一些材料。不了解没有办法做实验哦~
若觉文字太多,可直接阅读红体字~~

【实验必读材料】:

一、信号的基本概念:

每个进程在运行时,都要通过信号机制来检查是否有信号到达。若有,便中断正在执行的程序,转向与该信号相对应的处理程序,以完成对该事件的处理;处理结束后再返回到原来的断点继续执行

二、几个函数调用:

1、***Signal()**
预置对信号的处理方式,允许调用进程控制软中断信号
系统调用格式:signal(sig,function)
头文件为: #include <signal.h>
由于不同系统的信号编号是不完全相同的,所以当前系统中,可以使用“kill -l”命令查看信号编号。

下表仅供参考,不同系统信号不一样哦~:

名字说明
01SIGHUP挂起(hangup)
02SIGINT中断,当用户从键盘按ctrl+c或break键。
03SIGQUIT退出,当用户从键盘按quit键时
04SIGILL非法指令
05SIGTRAP跟踪陷阱(trace trap),启动进程,跟踪代码的执行
06SIGIOTIOT指令
07SIGEMTEMT指令
08SIGFPE浮点运算溢出
09SIGKILL杀死、终止进程
10SIGBUS总线错误
11SIGSEGV进程试图去访问其虚地址空间以外的位置
12SIGSYS系统调用中参数错,如系统调用号非法
13SIGPIPE向某个非读管道中写入数据
14SIGALRM闹钟。当某进程希望在某时间后接收信号时发此信号
15SIGTERM软件终止
16SIGUSR1用户自定义信号1
17SIGUSR2用户自定义信号2
18SIGCLD某个子进程死
19SIGPWR电源故障

2.****kill()**
系统调用格式:int kill(pid,sig)
参数定义
int pid,sig;
其中,pid是一个或一组进程的标识符,参数sig是要发送的软中断信号。
(1)pid>0时,操作系统将信号发送给进程pid。
(2)pid=0时,操作系统将信号发送给与发送进程同组的所有进程。
(3)pid=-1时,操作系统将信号发送给所有用户标识符真正等于发送进程的有效用户标识号的进程。

3、****lockf()**
头文件:#include <unistd.h>
允许将文件区域用作信号量(监视锁),或用于控制对锁定进程的访问(强制模式记录锁定)。试图访问已锁定资源的其他进程将返回错误或进入休眠状态,直到资源解除锁定为止。当关闭文件时,将释放进程的所有锁定,即使进程仍然有打开的文件。当进程终止时,将释放进程保留的所有锁定。

lockf(fd,1,0)是给文件上锁; lockf(fd,0,0)是给文件解锁;**

4、***pause()***
头文件:#include <unistd.h>
定义函数:int pause(void);
函数说明:pause()会令目前的进程暂停(进入睡眠状态), 直到被信号(signal)所中断.
返回值:只返回-1.
****

5、***waitpid()**
头文件
#include<sys/types.h>
#include<sys/wait.h>
如果在调用 waitpid()时子进程已经结束,则 waitpid()会立即返回子进程结束状态值。 子进程的结束状态值会由参数 status 返回,而子进程的进程识别码也会一起返回。如果不在意结束状态值,则参数 status 可以设成 NULL。参数 pid 为欲等待的子进程识别码,其他数值意义如下:**

pid数值解释
pid<-1等待进程组识别码为 pid 绝对值的任何子进程。
pid=-1等待任何子进程,相当于 wait()。
pid=0等待进程组识别码与目前进程相同的任何子进程。
pid>0等待任何子进程识别码为 pid 的子进程。

【实验目的】:

1.了解什么是信号,熟练掌握signal(),wait(),exit(),kill()函数。
2.熟悉并掌握Linux系统中进程之间采用软中断通信的基本原理。

【实验内容】:

一、编写一段程序,使用系统调用fork( )创建两个子进程,再用系统调用signal( )进行预置,让父进程捕捉由键盘发来的中断信号(即同时按下Ctrl+C键)。当系统捕捉到中断信号后,调用预置的stop函数,子进程捕捉到信号后,分别输出下列信息后终止:
Child process 1 is interrupted by parent!
Child process 2 is interrupted by parent!
父进程等待两个子进程终止后,输出以下信息后终止:
Parent process is interrupted!

参考代码:
# include<stdio.h>
# include<signal.h>
# include<unistd.h>
# include<sys/wait.h>
#include<stdlib.h>
int wait_mark;
void waiting()
{
   while(wait_mark!=0);
}
void stop()
{
   wait_mark=0;
}
int main()
{ 
  int  p1, p2;
  signal(SIGINT,stop); //signal()初始位置
  while((p1=fork())==-1);
  if(p1>0)
 {  
    while((p2=fork())==-1);
    if(p2>0)
    { 
      wait_mark=1;
      waiting( );      
      wait(0);
      wait(0);
      printf("parent process is interrupted!\n");
      exit(0);
    }
    else 
    {
        wait_mark=1;
        waiting( );
	lockf(1,1,0);
        printf("child  process 2 is interrupted by parent!\n");//可以输出多条语句试试看是否能插入其他进程的输出语句
        lockf(1,0,0);
        exit(0);
      }
  } 
   else
 {
    wait_mark=1;    
    waiting( );
    lockf(1,1,0);
    printf("child  process 1 is interrupted by parent!\n");//这里也可以输出多条语句试试看
    lockf(1,0,0);
    exit(0);
   }
}
运行结果:
yzy@yzy-virtual-machine:~/new$ ./a.out
^Cchild  process 2 is interrupted by parent!
child  process 1 is interrupted by parent!
parent process is interrupted!
分析结果:

1、系统调用signal( )进行预置,让父进程捕捉由键盘发来的中断信号,当系统捕捉到中断信号后,调用预置的stop函数,子进程捕捉到信号后,输出信息终止,(child1、child2输出顺序不定。)父进程等待两个子进程结束后,也输出信息终止
2、父进程用了两个wait(0)的原因:等待2个子进程都结束再执行

3、每个进程退出时都用了语句exit(0)的原因:正常运行程序并退出程序。为了保证每个进程执行完后,shell能及时回收资源。

二、修改并调试程序,增加语句signal(SIGINT,SIG_IGN)和语句signal(SIGQUIT,SIG_IGN),再观察程序执行时屏幕上出现的现象,并分析其原因。注意:实验前先用kill命令查询本机用户自定义信号的编号。
程序主要功能:子进程屏蔽外部中断信号(Ctrl-C);父进程接收用户按Ctrl-C产生的外部中断信号后,分别给两个子进程发信号(用户自定义信号)

参考代码:
# include<stdio.h>
# include<signal.h>
# include<unistd.h>
# include<sys/wait.h>
#include<stdlib.h>
int EndFlag,pid1,pid2;
void IntSend()
{
  kill(pid1,10);//向进程pid1发送用户自定义信号10
  kill(pid2,12);// 向进程pid2发送用户自定义信号12
  EndFlag=1;
}
void Print1()
{
   printf("child process 1 is interrupted by parent !\n");
   exit(0);
}
void Print2()
{
   printf("child process 2 is interrupted by parent !\n");
   exit(0);
}
int main()
{
 
     int exitcode;
     signal(SIGINT,SIG_IGN);
     signal(SIGQUIT,SIG_IGN);

	
while((pid1=fork())==-1);
if(pid1==0)
{ 
signal(SIGUSR1, Print1);     //用户自定义信号1
signal(SIGQUIT,SIG_IGN);
pause();
exit(0);
     }
else
     {
		while((pid2=fork())==-1);
   		if(pid2==0)
   		{
   		
  		signal(SIGUSR2, Print2);	  //用户自定义信号2
		signal(SIGQUIT,SIG_IGN);
		pause();
		exit(0);
    	}
   		else
    	{
    		signal(SIGINT, IntSend);
      		waitpid(-1,&exitcode,0);
      		printf("parent process is interrupted! \n");
      		exit(0);
} 
}}
运行结果
yzy@yzy-virtual-machine:~/new$ ./b.out
^Cchild process 1 is interrupted by parent !
child process 2 is interrupted by parent !
parent process is interrupted!
分析结果:

子进程屏蔽外部中断信号,父进程接收用户按“Ctrl+C”产生的外部中断信号后,分别给两个子进程发信号(用户自定义信号)。系统调用signal( )进行预置,子进程接收自定义信号后,调用预置的print函数,打印输出。(child1、child2顺序不定)。语句‘waitpid(-1,&exitcode,0)’代表父进程等待任何子进程,接收子进程状态结束值。等待子进程结束后,父进程打印输出,结束。

【实验总结】:

软中断通信:
了解了基本知识,硬中断,操作系统系统外设状态的变化。为了满足实时系统的要求,中断处理应该是越快越好。linux为了实现这个特点,当中断发生的时候,硬中断处理那些短时间就可以完成的工作,而将那些处理事件比较长的工作,放到中断之后来完成,也就是软中断来完成。基本的思路是: 父进程生成子进程,父进程发送信号并等待,子进程接收信号,然后自我终止并唤醒父进程,父进程再自我终止

心得体会:
通过本次实验我了解了软中断通信和管道通信进一步认识到了并发的实质,对Linux进程有了中断和通信更多的认识,学会了一些函数的应用,但是这只是很小一部分,我还需要课下多查阅资料,加强和巩固自己的学习。

**点赞的都是小可爱哦**~
请添加图片描述

Logo

鸿蒙生态一站式服务平台。

更多推荐