夯实基础(6):信号

144 阅读2分钟

发送信号是进程间最常见的通信方式。信号可由系统内核或者某个进程产生并发送给其它进程。进程收到信号,可以作出以下几种反应:执行信号的默认动作;忽略该信号;捕捉该信号并转向相应的信号处理函数。

#include<iostream>
#include<signal.h>
#include<unistd.h>
int main(){
    pid_t pid;
    pid = fork();
    if(pid < 0){
        cout<<"fork failed!"<<endl;
    }
    else if(pid == 0){
        cout<<"new progress: "<<getpid()<<endl;
        if(signal(SIGINT,SIG_IGN)){
            cout<<"can't receive SIGINT"<<endl;
        }
        if(signal(SIGTERM,SIG_DFL)){
            cout<<"can't receive SIGTERM"<<endl;
        }
        while(true){
            sleep(1);
            cout<<"sleep 1 second"<<endl;
        }
    }
    else 
    {
        cout<<"main progress: "<<getpid()<<endl;
        sleep(10);
        cout<<"send SIGINT"<<endl;
        kill(pid,SIGINT);
        cout<<"send SIGTERM"<<endl;
        sleep(10);
        kill(pid,SIGTERM);
    }
    return 0;
}

kill除了可以用作命令外,也可以作为函数使用,用来发送信号。上述代码中有两个进程,在主进程中,首先休眠10s,然后发送SIGINT信号,再次休眠10s后,发送SIGTERM信号。其中,前者被子进程忽略,后者则执行默认操作。通过分别追踪两个进程可以发现,主进程确实发送了两次信号,而子进程则收到了两个信号。子进程被SIGTERM信号终止,而主进程正常退出。 1.PNG signal函数的第二个参数是一个函数指针,表示相应的信号处理动作,可以预设为SIG_DFLSIG_IGN,也可以由用户自定义。当进程执行相应的信号处理动作时,如果又接收到相同信号,则系统会屏蔽该信号,由于信号有等待机制,待解除屏蔽后,仍可再次执行相应的信号处理动作。但无论屏蔽期间收到多少次相同信号,都只会认为收到了一次。
在UNIX中,提供了信号集数据类型sigset_t,可以保存信号的状态。进程可以通过该数据类型保存当前阻塞的信号。该数据类型其实是一个包含两个无符号长整型的结构体,每一位对应一种信号,0表示信号没来,1表示信号来了。同时,系统提供了一些信号相关函数:sigemptysetsigfillsetsigaddsetsigdesetsigprocmasksigismember