【Linux实验】软中断通信

发布于:2022-11-15 ⋅ 阅读:(616) ⋅ 点赞:(0)

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

在这里插入图片描述

其中用到的Linux系统函数文章末尾有讲解

在这里插入图片描述

# 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 killed!\n");
      exit(0);
    }
    else 
    {
        wait_mark=1;
        waiting( );
	    lockf(1,1,0);
        printf("child  process 2 is killed by parent!\n");
        lockf(1,0,0);
        exit(0);
    }
  } 
   else
 {
    wait_mark=1;    
    waiting( );
    lockf(1,1,0);
    printf("child  process 1 is killed by parent!\n");
    lockf(1,0,0);
    exit(0);
   }
}
  • 用 gcc 编译后再 ./ +文件名 运行即可
  • 键盘输入信号 CRTL+C 得到下图运行结果:

在这里插入图片描述

结果分析:

  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);
		} 
	}
}

运行结果:

^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为了实现这个特点,当中断发生的时候,硬中断处理那些短时间就可以完成的工作,而将那些处理事件比较长的工作,放到中断之后来完成,也就是软中断来完成。基本的思路是: 父进程生成子进程,父进程发送信号并等待,子进程接收信号,然后自我终止并唤醒父进程,父进程再自我终止。


其中用到的函数介绍:

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

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

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


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


本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到