kill只是杀进程吗?信号部分实战--系统开发必学linux基础知识

背景:

经常在做linux或者android系统开发中会用到kill这个命令 ,对于kill这命令可能很多同学理解都是只理解为“杀进程”,其实这个说法是不严谨的。所以还是非常有必要针对linux的信号基础知识进行相关的实战剖析讲解,让大家实战中对linux信号进行更加深入的认识。

信号:

信号,又称为软中断信号,是Linux系统响应某些条件而产生的一个事件。它是操作系统向一个进程或者线程发送的一种异步通知,用于通知该进程或线程某种事件已经发生,需要做出相应的处理。

下面我们分为两部分来给大家实战:信号的处理,信号的发送

信号的处理

信号处理理有三种,分别是忽略、捕捉和默认动作。主要对应方法是signal,具体可以使用man手册查看该方法

$ man signal


SIGNAL(2)                                                                                 Linux Programmer's Manual                                                                                 SIGNAL(2)

NAME
       signal - ANSI C signal handling

SYNOPSIS
       #include <signal.h>

       typedef void (*sighandler_t)(int);

       sighandler_t signal(int signum, sighandler_t handler);

DESCRIPTION
       The behavior of signal() varies across UNIX versions, and has also varied historically across different versions of Linux.  Avoid its use: use sigaction(2) instead.  See Portability below.

       signal() sets the disposition of the signal signum to handler, which is either SIG_IGN, SIG_DFL, or the address of a programmer-defined function (a "signal handler").

       If the signal signum is delivered to the process, then one of the following happens:

       *  If the disposition is set to SIG_IGN, then the signal is ignored.

       *  If the disposition is set to SIG_DFL, then the default action associated with the signal (see signal(7)) occurs.

       *  If  the disposition is set to a function, then first either the disposition is reset to SIG_DFL, or the signal is blocked (see Portability below), and then handler is called with argument signum.
          If invocation of the handler caused the signal to be blocked, then the signal is unblocked upon return from the handler.

       The signals SIGKILL and SIGSTOP cannot be caught or ignored.

RETURN VALUE
       signal() returns the previous value of the signal handler, or SIG_ERR on error.  In the event of an error, errno is set to indicate the cause.

ERRORS
       EINVAL signum is invalid.

忽略信号:进程可以选择忽略某些信号,即不对该信号进行任何处理,但是有两种信号不能被忽略(分别是 SIGKILL和SIGSTOP),因为他们向内核和超级用户提供了进程终止和停止的可靠方法,如果忽略了,那么这个进程就变成了没人能管理的的进程。

signal(SIGINT,SIG_IGN);//将SIGINT信号(ctrl+C、2)忽略

捕捉信号(自定义处理):进程可以注册一个信号处理函数来捕捉特定的信号,并在接收到该信号时执行相应的处理逻辑,说白了就是写一个信号处理函数,然后将这个函数告诉内核。当该信号产生时,由内核来调用用户自定义的函数,以此来实现某种信号的处理。

默认处理:如果进程没有注册信号处理函数且没有选择忽略信号,则系统会按照默认的处理方式来处理该信号。通常情况下,默认处理方式会导致进程终止或停止。
一般可以通过
signal(SIGINT,SIG_DFL);//将SIGINT信号(ctrl+C、2)变成默认处理方式

上面理论学习后,实战进行巩固:

信号处理方法函数signal原型

  #include <signal.h>

   typedef void (*sighandler_t)(int);

   sighandler_t signal(int signum, sighandler_t handler);

即正常使用中,只需要调用signal方法就可以,signum代表处理的信号值,sighandler_t代表具体的信号处理方法。
signum代表处理的信号值具体有哪些可以通过如下命令查看:

test@test:~/aosp15/frameworks$ 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	

这些都是SIG开头的,都有对应具体的整数值,每个值都有对应一个具体类型的信号,具体主要的信号含义可以通过如下命令查看:

man 7 signal


       Signal      Standard   Action   Comment
       ────────────────────────────────────────────────────────────────────────
       SIGABRT      P1990      Core    Abort signal from abort(3)
       SIGALRM      P1990      Term    Timer signal from alarm(2)
       SIGBUS       P2001      Core    Bus error (bad memory access)
       SIGCHLD      P1990      Ign     Child stopped or terminated
       SIGCLD         -        Ign     A synonym for SIGCHLD
       SIGCONT      P1990      Cont    Continue if stopped
       SIGEMT         -        Term    Emulator trap
       SIGFPE       P1990      Core    Floating-point exception
       SIGHUP       P1990      Term    Hangup detected on controlling terminal
                                       or death of controlling process
       SIGILL       P1990      Core    Illegal Instruction
       SIGINFO        -                A synonym for SIGPWR
       SIGINT       P1990      Term    Interrupt from keyboard
       SIGIO          -        Term    I/O now possible (4.2BSD)
       SIGIOT         -        Core    IOT trap. A synonym for SIGABRT
       SIGKILL      P1990      Term    Kill signal
       SIGLOST        -        Term    File lock lost (unused)
       SIGPIPE      P1990      Term    Broken pipe: write to pipe with no
                                       readers; see pipe(7)
       SIGPOLL      P2001      Term    Pollable event (Sys V).
                                       Synonym for SIGIO
       SIGPROF      P2001      Term    Profiling timer expired
       SIGPWR         -        Term    Power failure (System V)
       SIGQUIT      P1990      Core    Quit from keyboard
       SIGSEGV      P1990      Core    Invalid memory reference
       SIGSTKFLT      -        Term    Stack fault on coprocessor (unused)
       SIGSTOP      P1990      Stop    Stop process
       SIGTSTP      P1990      Stop    Stop typed at terminal
       SIGSYS       P2001      Core    Bad system call (SVr4);
                                       see also seccomp(2)
       SIGTERM      P1990      Term    Termination signal
       SIGTRAP      P2001      Core    Trace/breakpoint trap
       SIGTTIN      P1990      Stop    Terminal input for background process
       SIGTTOU      P1990      Stop    Terminal output for background process
       SIGUNUSED      -        Core    Synonymous with SIGSYS
       SIGURG       P2001      Ign     Urgent condition on socket (4.2BSD)
       SIGUSR1      P1990      Term    User-defined signal 1
       SIGUSR2      P1990      Term    User-defined signal 2

       SIGVTALRM    P2001      Term    Virtual alarm clock (4.2BSD)
       SIGXCPU      P2001      Core    CPU time limit exceeded (4.2BSD);
                                       see setrlimit(2)
       SIGXFSZ      P2001      Core    File size limit exceeded (4.2BSD);
                                       see setrlimit(2)
       SIGWINCH       -        Ign     Window resize signal (4.3BSD, Sun)

       The signals SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.

测试信号处理源码如下:

#include <iostream>
#include <signal.h>
#include <unistd.h>
void handler(int sig)
{
	if (sig == SIGINT) {
    	    std::cout<<"get a signal SIGINT"<<std::endl;
	    signal(SIGINT,SIG_DFL);//第二次发送就会直接默认中断该程序
	}
	else if (sig == SIGUSR1) {
	    std::cout<<"get a signal SIGUSR1"<<std::endl;
	    signal(SIGUSR1,SIG_IGN);//第二次发送就会忽略该信号
	}
	else if (sig == SIGKILL) {//压根不会进入
	   std::cout<<"get a signal SIGKILL"<<std::endl;
	}
}
int main()
{
    signal(SIGINT,handler);
    signal(SIGUSR1,handler);
    signal(SIGKILL,handler);//想针对SIGKILL也进行自定义处理,实际上是不生效的,无法自处理该信号
    while(true)
    {
        std::cout << "hello signal, pid: " << getpid() << std::endl;
        sleep(2);
    }
}

编译:

g++ signal_test.cpp -o signal_test

运行结果如下:

SIGINT信号的自定义和def处理相关验证
在这里插入图片描述针对SIGUSR1的SIG_IGN相关验证
在这里插入图片描述其实从这个SIGUSR1是不是也可以看出来信号其实也可以用于进程间的一种跨进程通讯方式,不过这种跨进程方式相对比较简单一些。
SIGKILL信号无法自定义处理相关验证
在这里插入图片描述

信号的发送

信号发送有多个方式,这里之介绍最常用的kill方法发送信号。平常把kill命令或kill函数被看作杀死是不恰当的,其实kill只是将一个信号发送给一个进程或进程组。具体可以看一下kill函数相关的手册说明:

man 2 kill

KILL(2)                                                                                   Linux Programmer's Manual                                                                                   KILL(2)

NAME
       kill - send signal to a process

SYNOPSIS
       #include <sys/types.h>
       #include <signal.h>

       int kill(pid_t pid, int sig);

   Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

       kill(): _POSIX_C_SOURCE

DESCRIPTION
       The kill() system call can be used to send any signal to any process group or process.

       If pid is positive, then signal sig is sent to the process with the ID specified by pid.

       If pid equals 0, then sig is sent to every process in the process group of the calling process.

       If pid equals -1, then sig is sent to every process for which the calling process has permission to send signals, except for process 1 (init), but see below.

       If pid is less than -1, then sig is sent to every process in the process group whose ID is -pid.

       If  sig is 0, then no signal is sent, but existence and permission checks are still performed; this can be used to check for the existence of a process ID or process group ID that the caller is per‐
       mitted to signal.

       For a process to have permission to send a signal, it must either be privileged (under Linux: have the CAP_KILL capability in the user namespace of the target process), or the real or effective user
       ID  of  the  sending process must equal the real or saved set-user-ID of the target process.  In the case of SIGCONT, it suffices when the sending and receiving processes belong to the same session.
       (Historically, the rules were different; see NOTES.)

RETURN VALUE
       On success (at least one signal was sent), zero is returned.  On error, -1 is returned, and errno is set appropriately.

上面注释就解释的很清楚,The kill() system call can be used to send any signal to any process group or process。
这里使用kill方法主要需要两个参数:
参数1 信号要发送给具体哪个pid,发送给哪个进程
参数2 具体要发送的信号类型

下面进行kill方法发送信号相关实战:

#include <iostream>
#include <cstdlib>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
    if(argc != 3)
    {
        std::cerr << "pleash input:pid and signum ;Usage: " << argv[0] << " signum pid" << std::endl;
        return 1;
    }
 
    pid_t pid = std::stoi(argv[2]);
    int signum = std::stoi(argv[1]);
    std::cout<<"pid :"<<pid<<"  signum: "<<signum<<std::endl;
    kill(pid, signum);//调用kill方法进行信号发送
}

编译:

 g++ func_kill.cpp  -o func_kill

验证如下:
在这里插入图片描述

总结:

上面针对linux信号的基础知识进行了相关的学习和巩固,并且也进行了相关的实战开发。主要对信号的概念介绍,信号的实战处理,信号的发送,上面也分享了相关的运行代码,大家可以直接在Ubuntu上进行编译验证,这个代码可以不需要在android平台编译运行。学习了信号相关知识以后,大家在平常看android系统相关信号处理,信号发送代码时候就不会那么陌生。

更多framework实战干货,请关注下面“千里马学框架”

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值