Linux信号学习笔记(1)

Linux信号学习笔记(1)

程序运行

  当如下代码在运行时如需中止这份程序有几种办法。

#include<unistd.h>
#include<stdio.h>
using namespace std;
int main()
{
    for(int i=1;i<=100;i++)
    {
        printf("time of programe running:%ds\n",i);
        sleep(1);
    }
}

1.  在运行程序的终端中使用"ctrl+c"组合键的方法可以终止:

~$ ./demo_1
time of programe running:1s
time of programe running:2s
time of programe running:3s
^C

2.  在程序运行时,使用终端(另开一个)中ps -ef|grep 进程关键字的方式得到进程号,再使用"kill 进程号"的方式终止:

~$ ps -ef|grep demo_1
mrlop     13554  13146  0 18:47 pts/0    00:00:00 ./demo_1
mrlop     13602  13524  0 18:47 pts/1    00:00:00 grep --color=auto demo_1
~$ kill 13554

  此时运行程序的终端中会有如下内容:

~$ ./demo_1
time of programe running:1s
time of programe running:2s
time of programe running:3s
已终止

3.  在程序运行时,使用"killall 进程关键字"的方式终止:

~$ killall demo_1

  此时运行程序的终端中会有如下内容:

~$ ./demo_1
time of programe running:1s
time of programe running:2s
time of programe running:3s
已终止

Linux信号

  由上述内容中,均是向"demo_1"程序发送信号将其终止,其中"ctrl+c"为发送SIGINT信号,kill和killall均是发送SIGTERM信号,其余信号及功能可以查询Linux信号表,使用"kill -l"指令可以得到Linux信号列表。

~$ kill -l
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

  所以SIGINT代码是2,SIGTERM代码是15,kill还可以使用"kill -信号代码 进程号"或"kill -信号名称 进程号"来向对应进程发送其他的信号,中间的参数不加则是发送SIGTERM信号。

signal函数

  使用signal.h库中声明的函数signal:

__sighandler_t signal (int __sig, __sighandler_t __handler)

  signal函数中第一个参数为信号名称或信号代码,第二个参数为收到信号时运行的处理函数名。signal函数的第二个参数还可以填写"SIGIGN"忽略该信号,"SIG_DFL"回复该信号的处理方式为默认。
  修改程序如下:

#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
using namespace std;
void handle(int sig)
{
    printf("receive signal:%d, program exit\n",sig);
    exit(0);
}
int main()
{
    signal(15,handle);
    for(int i=1;i<=100;i++)
    {
        printf("time of programe running:%ds\n",i);
        sleep(1);
    }
}

  运行时使用"killall demo_2"的方式结束进程,进程将收到15信号,对于15信号会交由handle函数进行处理。得到以下结果:

~$ ./demo_2
time of programe running:1s
time of programe running:2s
time of programe running:3s
receive signal:15, program exit

  但是值得注意的是,即使代码中添加了"signal(9,handle)",使用"kill -9 demo_2"时程序依旧会直接被kill,因为其中SIGKILL(9)和SIGSTOP(19)是不能被屏蔽的。

~$ ./demo_2
time of programe running:1s
time of programe running:2s
已杀死

kill函数

  c语言中提供了kill函数用于发送信号:

int kill (__pid_t __pid, int __sig)

  第一个参数为所要发送信号的目的进程号,第二个参数为所要发送信号的信号代码。如下代码父进程向子进程发送15信号。

#include<signal.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
using namespace std;
void handle(int sig)
{
    printf("receive signal:%d, my pid=%d, my parent pid=%d, program exit.\n",sig,getpid(),getppid());
    exit(0);
}
int main()
{
    int pid;
    pid=fork();
    if(pid>0)
    {
        printf("parent pid:%d.\n",getpid());
        sleep(1);
        kill(pid,15);
        sleep(2);
    }
    else
    {
        printf("child pid:%d.\n",getpid());
        signal(15,handle);
        sleep(2);
    }  
}

  为了避免信号发送的时机不对,以及父进程过早结束导致子进程getppid()获得的父进程号不一致使用了sleep()函数。可以得到如下运行结果:

~$ ./demo_3
parent pid:15694.
child pid:15695.
receive signal:15, my pid=15695, my parent pid=15694, program exit.
上一篇:修改vscode的Settings导致TERMINAL窗口不能使用


下一篇:Executors类创建四种常见线程池,实战java高并发程序设计第二版pdf