文章目录

  • 一、信号入门
    • 1.1 信号概念
    • 1.2 用 kill-l命令查看信号列表
    • 1.3 信号处理常见方式预览
  • 二、产生信号
    • 2.1 通过终端按键产生信号
    • 2.2 由于程序中存在异常产生信号
    • 2.3 系统接口调用产生信号
    • 2.4 软件条件产生信号
  • 三、阻塞信号
    • 3.1 信号相关常见概念补充
    • 3.2 在内核中的表示
    • 3.3 sigget_t及其操作函数
  • 四、处理信号
    • 4.1 内核如何实现信号的捕捉
    • 4.2 sigaction

一、信号入门

1.1 信号概念

信号是UNIX和Linux系统响应某些条件而产生的一个事件,接收到该信号的进程会相应地采取一些行动。信号是软中断,通常信号是由一个错误产生的。但它们还可以作为进程间通信或修改行为的一种方式,明确地由一个进程发送给另一个进程。一个信号的产生叫生成,接收到一个信号叫捕获。

信号是发送给具体的进程的,告诉进程要在合适的时候执行相应的动作。这要求进程具有识别信号的能力,并且知道收到一个信号时,应该做出什么反应,这些是在操作系统的源代码中就已经设置好了的。

但是,当进程收到某种信号时,该信号并不一定是被进程立刻处理的,因为进程此时可能在做更重要的事情。

当进程不能立刻处理接受到的信号时,该信号会被进程保存起来,以便该信号在合适的时候被进程处理。而这个信号是被进程保存在struct task_struct中的,信号的本质也是数据。也就是说,信号的发送本质上就是向进程的PCB中写入信号数据。

PCB是一个内核数据结构,用来定义进程对象。但是操作系统不相信任何人,那么信号数据是怎么写入PCB的呢?

答案是操作系统本身。所以无论信号如何发送,本质都是在底层通过操作系统发送的。

1.2 用 kill-l命令查看信号列表

[sny@VM-8-12-centos practice]$ kill -l1) SIGHUP  2) SIGINT   3) SIGQUIT  4) SIGILL   5) SIGTRAP6) 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

每个信号都有一个编号和一个宏定义名称,这些宏定义可以在signal.h中找到,例如其中有定 义 #define SIGINT 2
编号34以上的是实时信号,本章只讨论编号34以下的信号,不讨论实时信号。这些信号各自在什么条件下产生,默认的处理动作是什么,在signal(7)中都有详细说明: man 7 signal

1.3 信号处理常见方式预览

一般而言,进程收到信号的处理方案有三种。

①默认动作:终止进程、暂停进程等。
②忽略动作:不对进程做任何改变。
③自定义动作:用自己定义的接口替换到某一个进程原本应该让进程做出的反应(后文详细说明)。

二、产生信号

2.1 通过终端按键产生信号

当我们在Linux中编写的程序中包含死循环时,我们输入任何操作指令都不能让进程退出,除非输入ctrl+c这类指令,如下:

执行结果如下(该程序对应的Makefile太简单,这里就不粘贴了):

[sny@VM-8-12-centos practice]$ make clean;make
rm -f mytest
gcc -o mytest test.c
[sny@VM-8-12-centos practice]$ ls
Makefile  mytest  test.c
[sny@VM-8-12-centos practice]$ ./mytest
hello world!
hello world!
hello world!
^C

这里使用Ctrl +C的本质就是从键盘向进程发送2号信号,接下来简单地证明一下这个结论。

先了解一个函数接口:

这里的typedef void (*sighandler_t)(int)是一个函数指针,指针指向的函数可以完成对指定的信号在进程中执行动作的替换。
下面的sighandler_t signal(int signum, sighandler_t handler);是一个回调函数,第一个参数是某一个信号的编号,第二个参数是函数指针。使用这个函数就可以完成对于自己设定的信号执行动作的替换(类似qsort)。

举个例子:

执行结果如下:

[sny@VM-8-12-centos practice]$ ./mytest
hello world!
hello world!
hello world!
^Cget the signal: signal number:2 pid:28845
hello world!
hello world!
hello world!
^\Quit

可以看到,我们在代码中将2号信号的处理动作换为打印一条语句,而当我们输入Ctrl C的时候,进程没有退出,而是打印了这条语句,所以上面的结论是正确的!
注意,键盘产生的信号只能终止前台的进程,后台进程可以使用kill -9命令终止!9号信号不可被捕捉。

举个例子:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>void handler(int signo){switch(signo){case 2:                             printf("捕捉2号信号\n");          break;case 3:                             printf("捕捉3号信号\n");          break;                                                                                                                                         case 9:                             printf("捕捉9号信号\n");          break;                            default:                            break;                            }
}                                       int main()
{                                       for(int i=1;i<=31;i++)                {//可以捕捉所有信号                   signal(i,handler);                  }                                     while(1)                                                                                                                                  {                                                                                                                                             printf("hello world!\n");                                                                                                               sleep(2);                                                                                                                               }return 0;
}

执行结果如下:

至于为什么,下文再解释。

2.2 由于程序中存在异常产生信号

下面来写一个有明显错误的代码:

毫无疑问,最后一定会因为这个错误,导致该进程崩溃。
崩溃提示如下:

[sny@VM-8-12-centos practice]$ make clean;make
rm -f mytest
gcc -o mytest test.c
test.c: In function ‘main’:
test.c:34:6: warning: division by zero [-Wdiv-by-zero]a/=0;^
[sny@VM-8-12-centos practice]$ ./mytest
Floating point exception

这是一个浮点数错误。
接下来,将代码还原为2.1中最后的样子,并在handler函数稍作修改:

查看一下最后该进程收到的是几号信号。

[sny@VM-8-12-centos practice]$ make clean;make
rm -f mytest
gcc -o mytest test.c
test.c: In function ‘main’:
test.c:36:6: warning: division by zero [-Wdiv-by-zero]a/=0;^
[sny@VM-8-12-centos practice]$ ./mytest
捕捉8号信号

也就是说,这个浮点数错误导致进程收到了8号信号,进而导致进程退出。为什么?

答:因为程序中的任何计算都会有CPU的参与,如果程序中出现了问题,CPU都会将其记录在案。而软件上的错误最终会体现在硬件或者其他软件上。而操作系统时硬件的管理者,当硬件出现问题时,操作系统会找到出错的进程,并向进程发送信号,导致进程终止。

当一个进程崩溃时,我们最关心的是什么?

毫无疑问一定是崩溃的原因,这个原因根据上一个问题就可以知道。
除此之外,我们往往还想知道,到底是进程中的那一部分出错导致了崩溃。

在Linux中,当一个进程推出的时候,它的退出码和退出信号都会被设置;当一个进程异常的时候,进程的退出信号会被设置,表明当前进程推出的原因。如果有必要,操作系统会设置推出信息中的core dump标志位,并将进程在内存中的数据转储到磁盘中,方便我们后期调试。

可是好像在上面的例子中,并没有看到进程运行结束后,有提示程序中那一部分出错的现象。这是因为在云服务器上,关于core dump的文件是被关掉的,其他的机器情况可能不同。

[sny@VM-8-12-centos practice]$ ulimit -a
core file size          (blocks, -c) 0//core dump相关文件
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 7908
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 100001
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 7908
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

将其打开只需执行如下指令:

接下来再运行程序,最后显示地结果就会不一样,而且会在当前目录下生成一个该程序的可以支持调试的二进制文件,如下:

[sny@VM-8-12-centos practice]$ ./mytest
Floating point exception (core dumped)
[sny@VM-8-12-centos practice]$ ll
total 136
-rw------- 1 sny sny 249856 Jan 17 20:45 core.26796
-rw-rw-r-- 1 sny sny     63 Jan 17 17:02 Makefile
-rwxrwxr-x 1 sny sny   8408 Jan 17 20:45 mytest
-rw-rw-r-- 1 sny sny    607 Jan 17 20:45 test.c

但是现在仍然没有显示到底是那个地方出错了,为了知道出错的地方,要调试起来,将Makwfile文件内容稍作修改:

然后运行程序,并开始调试,用生成的二进制文件进行调试:

[sny@VM-8-12-centos practice]$ gdb mytest
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-120.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/sny/code/practice/mytest...done.
(gdb) core-file core.26796
[New LWP 26796]
Core was generated by `./mytest'.
Program terminated with signal 8, Arithmetic exception.
#0  0x0000000000400595 in main () at test.c:36
36      a/=0;
Missing separate debuginfos, use: debuginfo-install glibc-2.17-326.el7_9.x86_64

但是并不是所有的程序都会生成core文件,具体取决于该进程的core dump是否为1,举个例子查看core dump:

结果如下:

[sny@VM-8-12-centos practice]$ ./mytest
子进程!
exit code:0 exit signal:8 core dump:1

2.3 系统接口调用产生信号

我们也可以直接调用系统接口kill来产生信号:

样例代码如下:

接下来做以下操作:

可以看到,刚开始右边有一个sleep进程,但是当我们用左边的程序给sleep进程发送了9号信号之后,sleep进程就不存在了。因为它接收到了9号信号,所以退出。
以上就是通过系统接口发送信号的全过程。

第二个接口为raise,它的作用是给进程本身发送信号:

样例代码如下:

int main()
{while(1){printf("This is a process!\n");sleep(2);raise(9);                                                                                                                                        }
}

结果如下:

[sny@VM-8-12-centos practice]$ ./mytest
This is a process!
Killed

第三个接口abort是给进程本身发送6号信号,这个读者可以用捕捉信号的代码自己验证一下,由于代码大量相同,这里就不粘贴了。

2.4 软件条件产生信号

这种信号一般是通过某种软件(操作系统),来触发信号的发送,系统层面设置定时器,或者某种操作而导致条件不就绪等这样的场景下,触发的信号发送。比如:进程间通过管道通信时,读端关闭,写端还在写时,就会触发信号发送,关闭写端。

这里用到的接口是alarm:

这个接口的参数是时间,表示在一段时间之后向进程发送一个信号(14号信号),返回值为剩余的时间(秒)。

举个例子:

结果如下:

[sny@VM-8-12-centos practice]$ make clean;make
rm -f mytest
gcc -o mytest test.c -g
[sny@VM-8-12-centos practice]$ ./mytest
This is a process,ret:0
res:25
This is a process,ret:0
res:0

如果没有设置alarm的模拟动作,则会执行默认动作,终止进程。
看一个例子:

这段代码是要统计一秒内能对count递增到多少,结果如下:

虽然信号产生的方式很多,但最终一定都是通过操作系统向目标进程发送的信号。

如何理解操作系统向进程发送信号?

前面说过,在PCB中一定有对应的数据变量,来保存进程是否收到了对应的信号。
其实,这个数据变量是一个位图结构,也就是说用一个数字的每一个比特位是否为1表示该进程是否收到某一个信号。
所以,操作系统向进程发送信号本质就是,向PCB中的信号位图写入比特位1。


三、阻塞信号

3.1 信号相关常见概念补充

实际执行信号的处理动作称为信号递达(Delivery)
信号从产生到递达之间的状态,称为信号未决(Pending)。
进程可以选择阻塞 (Block )某个信号。
被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.
注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

3.2 在内核中的表示

上图中的pending就是前面解释过的位图结构,用来表示是否接收到某信号,而handler本质上是一个函数指针数组,其中每一个指针都指向一个参数为一个整形值,无返回值的函数,就类似于我们前面实现的handler函数。
当函数参数为0或1时,进程就对该信号进行默认和忽略操作,如果是其他值,就把指向的函数地址填入handler,以便做出对应的反应。

操作系统下定义的SIG_DFL和SIG_IGN如下:

[sny@VM-8-12-centos practice]$ grep -ER 'SIG_DFL|SIG_IGN' /usr/include/
/usr/include/asm-generic/signal-defs.h:#define SIG_DFL  ((__sighandler_t)0) /* default signal handling */
/usr/include/asm-generic/signal-defs.h:#define SIG_IGN  ((__sighandler_t)1) /* ignore signal */

而block表本质上也是一个位图结构,比特位的位置代表信号的编号,比特位内容表示是否收到了该信号。

进程在处理某一个信号的时候,首先要确定block和pending是否为1,同时为1则表示该进程被阻塞,若block为0,pending为1表示该信号可以被递达,也就可以进行具体的操作。

所以,上面的那张表应该横着看。

3.3 sigget_t及其操作函数

每个信号只有一个bit的未决标志,非0即1,不记录该信号产生了多少次,阻塞标志也是这样表示的。
因此,未决和阻塞标志可以用相同的数据类型sigset_t来存储,sigset_t称为信号集,这个类型可以表示每个信号的“有效”或“无效”状态,在阻塞信号集中“有效”和“无效”的含义是该信号是否被阻塞,而在未决信号集中“有效”和“无效”的含义是该信号是否处于未决状态。下一节将详细介绍信号集的各种操作。 阻塞信号集也叫做当前进程的信号屏蔽字(Signal Mask),这里的“屏蔽”应该理解为阻塞而不是忽略。

虽然sigset_t是一个位图结构,但是不同的操作系统的具体实现是不一样的,但都不能让用户直接修改该变量,所以就需要使用一些特定的函数。

#include <signal.h>
int sigemptyset(sigset_t *set);
int sigfillset(sigset_t *set);
int sigaddset (sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(const sigset_t *set, int signo);

函数sigemptyset初始化set所指向的信号集,使其中所有信号的对应bit清零,表示该信号集不包含 任何有效信号。
函数sigfillset初始化set所指向的信号集,使其中所有信号的对应bit置位,表示 该信号集的有效信号包括系统支持的所有信号。
注意,在使用sigset_ t类型的变量之前,一定要调 用sigemptyset或sigfillset做初始化,使信号集处于确定的状态。初始化sigset_t变量之后就可以在调用sigaddset和sigdelset在该信号集中添加或删除某种有效信号。

这四个函数都是成功返回0,出错返回-1。sigismember是一个布尔函数,用于判断一个信号集的有效信号中是否包含某种 信号,若包含则返回1,不包含则返回0,出错返回-1。

sigprocmask:

调用函数sigprocmask可以读取或更改进程的信号屏蔽字(阻塞信号集)。

#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oset);

返回值:若成功则为0,若出错则为-1。

如果oset是非空指针,则读取进程的当前信号屏蔽字通过oset参数传出。如果set是非空指针,则 更改进程的信号屏蔽字,参数how指示如何更改。如果oset和set都是非空指针,则先将原来的信号 屏蔽字备份到oset里,然后根据set和how参数更改信号屏蔽字。假设当前的信号屏蔽字为mask,下表说明了how参数的可选值。


举个例子:

#include <stdio.h>
#include <signal.h>
#include <unistd.h> int main()
{sigset_t iset,oset;sigemptyset(&iset);sigemptyset(&oset);sigaddset(&iset,2);//屏蔽2号信号                                                                                                                   sigprocmask(SIG_SETMASK,&iset,&oset);  while(1)                               {                                      printf("hello world!\n");            sleep(3);                            }                                      return 0;
}

结果如下:

[sny@VM-8-12-centos practice]$ make clean;make
rm -f mytest
gcc -o mytest test.c -g
[sny@VM-8-12-centos practice]$ ./mytest
hello world!
hello world!
^Chello world!//输入2号信号对应操作,继续打印信息,2号信号被阻塞
^\Quit

注意,这样的操作同样对9号信号不起作用!

sigpending:


读取当前进程的未决信号集,通过set参数传出。调用成功则返回0,出错则返回-1。

举个例子:

上面代码的意思是先屏蔽2号信号,这样2号信号就不会被递达。
当进程跑起来时,pending中将全为0,而当向进程发送2号信号之后,pending中第二个比特位将会为1。

结果如下:

[sny@VM-8-12-centos practice]$ make clean;make
rm -f mytest
gcc -o mytest test.c -g
[sny@VM-8-12-centos practice]$ ./mytest
0000000000000000000000000000000
0000000000000000000000000000000
^C0100000000000000000000000000000
0100000000000000000000000000000
^\Quit

可见,结果和预计相同。

四、处理信号

4.1 内核如何实现信号的捕捉

前面说过,信号被收到之后,进程会在合适的时候进行相关的操作,那么什么时候才是合适的时候呢?
答案是当进程从内核态转变为用户态的时候,这个时候,进程就会先在PCB中的pending位图里检测收到的信号,并做出处理。

内核态:执行操作系统的代码和数据时所处的状态
用户态:执行用户的代码和数据时所处的状态

它们的区别在于,内核态的权限要远远大于用户态的权限。

下面来详细地解释一下内核态和用户态:
在我之前的文章关于Linux中----进程优先级、环境变量和进程地址空间中解释过:每一个i昵称都有自己的虚拟空间,这些虚拟地址会经过页表和MMU映射到具体的物理内存。而每一个进程都有自己的虚拟空间和页表,这也保证了不同的进程不会占用同一块资源。

但是,在虚拟地址空间中除了有3GB的用户空间之外,还有1GB的内核空间,如下:

虽然每一个进程都有4GB的虚拟地址空间,但是并不意味着它们都可以随时随地访问这些空间。

上面说的页表指的是用户级页表,每个进程都有。实际上,还有一个内核级页表。这个页表被所有进程共享,但是共享不代表可以访问

只有当进程处于内核态时,才能经过那1GB的内核空间和内核级页表的映射访问到物理内存中属于操作系统的代码和数据。这也就是所谓的“权限的不同”。

当进程从用户态转变为内核态时,操作系统处理完所有的异常之后准备返回用户态之前,就会检测当前进程中的PCB的pending位图。如果某一信号的处理动作时自定义的,则返回用户态执行信号处理函数,然后再通过特殊的系统调用进入内核态,最后再返回用户态中上次中断的地方继续向下执行。

如图:

为什么一定要切换为用户态才能执行信号捕捉方法呢?

理论上来说,操作系统是可以执行用户的代码的。但是操作系统不相信任何人,为了防止操作系统执行的用户代码里存在恶意危害操作系统的代码的情况出现,每次执行信号捕捉代码都需要切换为用户态。

4.2 sigaction

#include <signal.h>
int sigaction(int signo, const struct sigaction *act, struct sigaction *oact);

sigaction函数可以读取和修改与指定信号相关联的处理动作。调用成功则返回0,出错则返回- 1。signo是指定信号的编号。若act指针非空,则根据act修改该信号的处理动作。若oact指针非 空,则通过oact传出该信号原来的处理动作。act和oact指向sigaction结构体。

将sa_handler赋值为常数SIG_IGN传给sigaction表示忽略信号,赋值为常数SIG_DFL表示执行系统默认动作,赋值为一个函数指针表示用自定义函数捕捉信号,或者说向内核注册了一个信号处理函 数,该函数返回值为void,可以带一个int参数,通过参数可以得知当前信号的编号,这样就可以用同一个函数处理多种信号。显然,这也是一个回调函数,不是被main函数调用,而是被系统所调用。

举个例子:

结果如下:

[sny@VM-8-12-centos practice]$ make clean;make
rm -f mytest
gcc -o mytest test.c -g
[sny@VM-8-12-centos practice]$ ./mytest
hello world!
hello world!
^C捕捉到2号信号
hello world!
hello world!
^\Quit

可以看到,这个方法跟之前介绍过的方法没有什么不同。

当某个信号的处理函数被调用时,内核自动将当前信号加入进程的信号屏蔽字,当信号处理函数返回时自动恢复原来的信号屏蔽字,这样就保证了在处理某个信号时,如果这种信号再次产生,那么 它会被阻塞到当前处理结束为止。 如果在调用信号处理函数时,除了当前信号被自动屏蔽之外,还希望自动屏蔽另外一些信号,则用sa_mask字段说明这些需要额外屏蔽的信号,当信号处理函数返回时自动恢复原来的信号屏蔽字。

【关于Linux中----信号】相关推荐

  1. linux中的信号是什么意思,linux中信号的基本概念

    1.信号的基本概念: 信号全称为软中断信号,也有人称作软中断,信号机制是进程之间相互传递消息的一种方法. 2.信号的作用: 进程之间可以互相通过系统调用kill发送软中断信号,通知进程发生了某个事件. ...

  2. linux中信号的处理,linux中关于信号处理笔记(二)

    2 等待一个全局变量被设置 这种情况是等待一个信号处理程序设置一个全局变量.下面的例子用于捕捉中断信号和退出信号,但是希望仅当退出信号处理程序时,才唤醒主进程. #include #include # ...

  3. Linux 中 信号signal 及其产生原因

    输入 kill -l 查看所有的信号 其中每个信号的产生原因 转自 http://blog.csdn.net/wesleyluo/article/details/5279482 信号 取值 默认动作 ...

  4. linux所有信号,【转载】Linux 信号列表

    信号及其简介 信号是一种进程通信的方法,他应用于异步事件的处理.信号的实现是一种软中断.它被发送为一个正在运行的进程,已告知进程某个事件发生了. SIGHUP 本信号在用户终端连接(正常或非正常)结束 ...

  5. linux内核定义的常用信号6,Linux中的信号

    在 Linux 中,理解信号的概念是非常重要的.这是因为,信号被用于通过 Linux 命令行所做的一些常见活动中.例如,每当你按 Ctrl+C 组合键来从命令行终结一个命令的执行,你就使用了信号.每当 ...

  6. linux中signal函数返回值,signal函数、sigaction函数及信号集操作函数

    信号是与一定的进程相联系的.也就是说一个进程可以决定在进程中对哪些信号进行什 么样的处理.例如一个进程可以忽略某些信号而只处理其他一些信号另外一个进程还可以选择如何处理信号.总之这些总与特定的进程相联 ...

  7. linux中脚本扑捉(trap)信号问题

    linux中脚本扑捉(trap)信号问题 扑捉ctrl+c信号: 1 #!/bin/bash 2 trap "trap" 2; 3 function trap() 4 { 5 ec ...

  8. linux通过信号回调函数,信号机制的管理结构 - Linux内核中的信号机制_Linux编程_Linux公社-Linux系统门户网站...

    信号只是一个数字,数字为0-31表示不同的信号,如下表所示. 编号 信号名 默认动作 说明 1 SIGHUP 进程终止 终端断开连接 2 SIGINT 进程终止 用户在键盘上按下CTRL+C 3 SI ...

  9. 在linux系统中 下列哪些信号无法捕获,下列哪个选项不是 Linux 系统中信号的状态。...

    下列哪个选项不是 Linux 系统中信号的状态. 更多相关问题 通 过 和他人的 谈话 . 观 察 市场 情况 等也 可以 获得 大量 的信 息 , 特 别 是 通过 人们 在日常生活 中 的 抱 怨 ...

最新文章

  1. 采购定价过程字段解析
  2. 云监控Agent指南-Linux版
  3. 如何以及何时使用例外
  4. A5D2 GPIO测试
  5. 大数据学习(10)--流计算
  6. Nginx服务架构初探(七):nginx邮件服务
  7. weihan talk
  8. Xcode 静态库调试策略
  9. C语言学习笔记---结构体指针
  10. PAT1023. 组个最小数
  11. Linux iostat和vmstat命令
  12. 再谈 MySQL 备份
  13. 【Python】106页的《python进阶》,附下载
  14. 美图秀秀图片修改成圆角
  15. 作为一个程序员,你居然不知道内存(DRAM)的工作原理,这样能跟上时代的进步吗?
  16. python 批量创建文件夹
  17. 从发声机理到听觉感知认识声音的本质
  18. 超百个区块链应用落地福州,BSN助力数字应用第一城蓬勃发展
  19. linux查看ftp客户端限速配置,vsftpd限速设置
  20. 计算机网络——域名系统

热门文章

  1. Arduino Uno基础入门01(认识Arduino)
  2. 基于卷积神经网络的信用卡欺诈侦测
  3. Hibernate——大量save()效率低下的解决方法
  4. Unity3d UGUI 实现底部UI自适应的功能(含工程)
  5. JAVA流程控制(2021-07-11)
  6. 从键盘输入一个大写字母,转换成小写字母
  7. 一看就会☀️Go异常处理recover,panic
  8. 论文阅读:(2020 AAAI) Video Cloze Procedure for Self-Supervised Spatio-Temporal Learning
  9. 《Introduction to Linux》——Linux Fundation (10~14/18章)
  10. 内是独体字还是半包围_包是独体字还是半包围包是独体字还是半包围结构