【操作系统】进程通信(一)信号

126 阅读4分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情 这也是第17篇文章

关于信号的一些基本概念及思考

软中断

在早期的UNIX版本中,信号又被称为软中断。

Q:为什么会被称为软中断?

A:因为它的表现和中断类似。若进程检测到有信号到达,就中断当前程序,转向对信号事件的处理,之后才又恢复现场,继续处理原来的事件。

信号的在代码中的形式和体现是如何的?

每个信号都对应一个正整数常量,即sigal number(信号编号),这是进程之间事先约定的信息的类型。写在了头文件<signal.h>中。 以下是信号的类型:

为0时表示没有任何信号。

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

信号与中断的异同

类型
信号无优先级;用户态 ;响应有较大延迟都是相同的异步通信方式;都可被屏蔽
中断有优先级 ;核心态;响应及时

信号的作用机制

信号的发送

指的是将目标进程的信号域中的信号位置1。

这个域有多个bit,每个bit对应一种信号类型。一个进程可以同时接收多种不同类型的信号(因为可以对不同位置1),但是对于多个同一类型的信号,只会记住其中一个(因为对同一位重复置1没有意义)

在代码中,一个进程调用kill(pid_t pid,int sig)向别的进程发送信号。 函数的使用方法如下:

  • pid==0,表示发送给同组的所有进程。
  • pid>0,发送给指定的pid号的进程
  • pid==-1,发送给所有用户标识符真正等于发送进程的有效用户标识号的进程,也就是 所有调用进程有权给其发送信号的进程,除了进程1(init)

信号的处理

前面提到,信号是可屏蔽的 ,如何屏蔽呢?在函数调用

void (*signal(int sig, void (*func)(int)))(int) 中,声明了进程对信号量的处理方式。

  • func为0是默认值,表示执行信号内容
  • func为1表示要忽略信号
  • 由于func是一个指向函数的指针,所以如果这个func表示的不是一个值而是一个函数,就执行这个函数(称为捕捉(catch)一个信号)。

示例程序

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <wait.h>
 
void waiting( );
void stop( );
int wait_mark;

void main( )
{
    int p1,p2,stdout;
    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;
    printf("Child process 2 is killed by parent!\n");
    signal(17,stop);   /*接收到软中断信号17,转stop*/
    waiting( );
    
    lockf(stdout,1,0);
    lockf(stdout,0,0);

    exit(0);

}
}

else{
    wait_mark=1;
    printf("Child process 1 is killed by parent!\n");
    signal(16,stop);        /*接收到软中断信号16,转stop*/
    waiting( );
    lockf(stdout,1,0);
    lockf(stdout,0,0);
    exit(0);
}  
}

 

void waiting( )
{
 while(wait_mark!=0);
}

void stop( )
{
wait_mark=0;
}

输出结果:

image.png