按下 CTRL + C之后,命令行中的前台进程会被终止。为什么???
信号是一种“软件中断”,用来处理异步事件
信号是一种类型的进程间通信方式(一个进程向另外一个进程发送信号)
硬件异常
内核检测到硬件错误,发送相应信号给相关进程
终端信号(用户交互信号,最典型:ctrl+c)
在终端输入 “特殊字符” 等价于向前台进程组发送信号
软件信号
在软件层面(进程代码中)触发的信号(发送给自身或其他进程)
硬件异常信号
信号 | 值 | 说明 |
SIGBUS | 7 | 总线错误,进程发生了内存访问错误 |
SIGFPE | 8 | 算术错误,FPE表示浮点异常 |
SIGILL | 9 | 指令错误,进程尝试执行非法指令 |
SIGSEGV | 11 | 段错误,进程访问了非法内存区域 |
终端相关信号
软件相关信号
内核与信号
1.内核检测到相关的错误,将信号发送给对应的进程。
2.进程可以通过系统调用,告诉内核,自己需要信号。比如:时钟信号。比如进程A告诉内核,我需要时钟信号,那么内核就定期给进程A发送时钟信号。
3.进程间通信:进程A通过内核 将信号 发送给进程B
信号的发送与处理,无非就是以上三种情况。
默认处理方式 | 说明 | 示例 |
ignore | 进程丢弃信号不会产生任何影响 | SIGCHLD SIGURG |
terminate | 终止进程 | SIGKILL SIGHUP |
coredump | 终止进程并产生转储文件 | SIGQUIT SIGILL |
stop/continue | 停止进程执行/恢复进程执行 | SIGSTOP,SIGCONT |
知识加油站:System V vs BSD
System V :也被称为 AT&T SystemV,是Unix操作系统众多版本中的一支
BSD :加州大学巴克利分校开创,Unix衍生系统,代表由此派生出的各种套件集合
Linux之所以被称为类Unix操作系统(Unix Like),部分原因就是Linux的操作风格是介于上述二者之间,且不同的厂商为了照顾不同的用户,其发行版本的操作风格有存在差异。
#include
#include
int kill(pid_t pid,int sig);
//pid > 0 ==> 发送信号给进程 ,pid == 0 ==> 发送信号给进程组 ,pid < -1 比如-1000,将信号发送给PGID为-1000的进程组
int raise(int sig); //信号处理完毕才返回
notes:
标准信号是unix系统中的信号,编号范围从1到31。
实时信号是Linux独有的信号,编号范围从32到64。
下面来看几个demo示例。
signal
可以看到在终端按下 CTRL + C 之后,信号处理函数 signal_handler就不断地调用。然后按下 CTRL + \ 后退出。
sysv_signal
- #define _GNU_SOURCE
- #include
- #include
- #include
- #include
- #include
-
- void signal_handler(int sig)
- {
- printf("handler : sig = %d\n",sig);
- }
-
- int main(void)
- {
- //signal(SIGINT,signal_handler);
- sysv_signal(SIGINT,signal_handler);
-
- while(1)
- {
- sleep(1);
- }
-
- return 0;
- }
- zhaixue@ubuntu:~/DTLinux/0-11$ gcc main.c -o main.out
- zhaixue@ubuntu:~/DTLinux/0-11$ ./main.out
- ^Chandler : sig = 2
- ^C
- zhaixue@ubuntu:~/DTLinux/0-11$
sysv_signal 按下一次 CTRL + C 就已经退出了。
bsd_signal
- //#define _GNU_SOURCE
- #define _XOPEN_SOURCE 600
- #define _POSIX_C_SOURCE 200800L
-
- #include
- #include
- #include
- #include
- #include
-
- void signal_handler(int sig)
- {
- printf("handler : sig = %d\n",sig);
- }
-
- int main(void)
- {
- //signal(SIGINT,signal_handler);
- //sysv_signal(SIGINT,signal_handler);
- bsd_signal(SIGINT,signal_handler);
-
- while(1)
- {
- sleep(1);
- }
-
- return 0;
- }
- zhaixue@ubuntu:~/DTLinux/0-11$ gcc main.c -o main.out
- zhaixue@ubuntu:~/DTLinux/0-11$ ./main.out
- ^Chandler : sig = 2
- ^Chandler : sig = 2
- ^Chandler : sig = 2
- ^Chandler : sig = 2
- ^Chandler : sig = 2
- ^Chandler : sig = 2
- ^Chandler : sig = 2
- ^\Quit (core dumped)
- zhaixue@ubuntu:~/DTLinux/0-11$
由于信号在表现形式上是一个整数值,所以将值为40的信号映射到 信号处理函数 signal_handler上来。
main.c
- //#define _GNU_SOURCE
- #define _XOPEN_SOURCE 600
- #define _POSIX_C_SOURCE 200800L
-
- #include
- #include
- #include
- #include
- #include
-
- void signal_handler(int sig)
- {
- printf("handler : sig = %d\n",sig);
- }
-
- int main(void)
- {
- signal(SIGINT,signal_handler);
- signal(40,signal_handler);
- //sysv_signal(SIGINT,signal_handler);
- //bsd_signal(SIGINT,signal_handler);
-
- while(1)
- {
- sleep(1);
- }
-
- return 0;
- }
想发送值为40的信号给信号处理函数。signal(40,signal_handler);
test.c
- #include
- #include
- #include
- #include
- #include
-
- int main(int argc,char* argv[])
- {
- int pid = atoi(argv[1]);
- int sig = atoi(argv[2]);
-
- printf("send sig(%d) to process(%d)...\n",sig,pid);
-
- kill(pid,sig); //send signal
-
- raise(SIGINT); //end execute
-
- while(1)
- {
- printf("while...\n");
- sleep(1);
- }
-
- return 0;
- }
编译输出:
- zhaixue@ubuntu:~/DTLinux/0-11$ gcc main.c -o main.out
- zhaixue@ubuntu:~/DTLinux/0-11$ ./main.out &
- [1] 9437
- zhaixue@ubuntu:~/DTLinux/0-11$ gcc test.c -o test.out
- zhaixue@ubuntu:~/DTLinux/0-11$ ./test.out 9437 40
- send sig(40) to process(9437)...
- handler : sig = 40
-
- zhaixue@ubuntu:~/DTLinux/0-11$
信号从 test.out 进程发送到 main.out 进程了。这也是一种进程间通信的方式了。
以上signal、sysv_signal、bsd_signal 三种自定义信号处理函数有什么区别?
System V风格的signal函数,注册的信号处理是一次性的。
在信号处理函数执行期间,很有可能再次收到当前信号
即:处理A信号的时候,再次收到A信号
对于 System V风格的 signal 函数,会引起信号处理函数的重入
即:调用处理函数的过程中,再次触发处理函数的调用
在注册信号处理函数时:
System V风格的 signal 不屏蔽任何信号
BSD风格的 signal 会屏蔽当前注册的信号
问题:BSD风格的 signal 函数,处理A信号期间,如果收到B信号会发生什么?
系统调用重启特性
系统调用期间,可能受到信号,此时进程必须从系统调用中返回
对于执行时间较长的系统调用(write / read),被信号中断的可能性很大
如果希望信号处理之后,被中断的系统调用能够重启,则:
可以通过条件 errno == EINTR 判断重启系统调用
-System V风格的 signal 函数(只能手动重启)
系统调用被信号中断后,直接返回 -1,并且 errno == EINTR
-BSD风格的 signal 函数(自动重启)
系统调用被中断,内核在信号处理函数结束后,自动重启系统调用
OneShot特性,只有System V风格的 signal 函数才有。
main.c
- #define _GNU_SOURCE
- //#define _XOPEN_SOURCE 600
- //#define _POSIX_C_SOURCE 200800L
-
- #include
- #include
- #include
- #include
- #include
-
- void signal_handler(int sig)
- {
- printf("handler : sig = %d\n",sig);
- }
-
- int main(void)
- {
- //signal(SIGINT,signal_handler);
- //signal(40,signal_handler);
- sysv_signal(SIGINT,signal_handler);
- //bsd_signal(SIGINT,signal_handler);
-
- while(1)
- {
- sleep(1);
- }
-
- return 0;
- }
编译运行:
- zhaixue@ubuntu:~/DTLinux/0-11$ gcc main.c -o main.out
- zhaixue@ubuntu:~/DTLinux/0-11$ ./main.out
- ^Chandler : sig = 2
- ^C
- zhaixue@ubuntu:~/DTLinux/0-11$
-
可以看到,只按下了一次 ctrl + c ,进程就退出了。因为 sysv_signal(SIGINT,signal_handler); 是一次性的,一旦 signal_handler 信号处理函数被调用了,那么这个信号处理函数:signal_handler 就已失效了。
接下来,我们接着实验 BSD风格的信号处理函数。
- //#define _GNU_SOURCE
- #define _XOPEN_SOURCE 600
- #define _POSIX_C_SOURCE 200800L
-
- #include
- #include
- #include
- #include
- #include
-
- void signal_handler(int sig)
- {
- printf("handler : sig = %d\n",sig);
- }
-
- int main(void)
- {
- //signal(SIGINT,signal_handler);
- //signal(40,signal_handler);
- //sysv_signal(SIGINT,signal_handler);
- bsd_signal(SIGINT,signal_handler);
-
- while(1)
- {
- sleep(1);
- }
-
- return 0;
- }
- zhaixue@ubuntu:~/DTLinux/0-11$ gcc main.c -o main.out
- zhaixue@ubuntu:~/DTLinux/0-11$ ./main.out
- ^Chandler : sig = 2
- ^Chandler : sig = 2
- ^Chandler : sig = 2
- ^Chandler : sig = 2
- ^Chandler : sig = 2
- ^Chandler : sig = 2
- ^Chandler : sig = 2
- ^Chandler : sig = 2
- ^Chandler : sig = 2
- ^\Quit (core dumped)
- zhaixue@ubuntu:~/DTLinux/0-11$
可以看到每次按下 ctrl + c,就会调用一次 信号处理函数。Linux中默认的信号处理函数 signal 和 BSD风格的信号处理函数行为是一致的。
main.c
- #define _GNU_SOURCE
- //#define _XOPEN_SOURCE 600
- //#define _POSIX_C_SOURCE 200800L
-
- #include
- #include
- #include
- #include
- #include
-
- void delay_handler(int sig)
- {
- int i = 0;
-
- printf("begin delay handler...\n");
-
- for(i=0;i<5;i++)
- {
- printf("sleep %d ...\n",i);
- sleep(1);
- }
-
- printf("end delay handler...\n");
- }
-
- void signal_handler(int sig)
- {
- printf("handler : sig = %d\n",sig);
- }
-
- int main(void)
- {
- //signal(SIGINT,signal_handler);
- //signal(40,signal_handler);
- sysv_signal(SIGINT,delay_handler);
- //bsd_signal(SIGINT,signal_handler);
-
- while(1)
- {
- sleep(1);
- }
-
- return 0;
- }
- zhaixue@ubuntu:~/DTLinux/0-11$ gcc main.c -o main.out
- zhaixue@ubuntu:~/DTLinux/0-11$ ./main.out
- ^Cbegin delay handler...
- sleep 0 ...
- sleep 1 ...
- sleep 2 ...
- sleep 3 ...
- sleep 4 ...
- end delay handler...
- ^C
- zhaixue@ubuntu:~/DTLinux/0-11$
-
可以看到这一次 oneShot特性。
- zhaixue@ubuntu:~/DTLinux/0-11$ gcc main.c -o main.out
- zhaixue@ubuntu:~/DTLinux/0-11$ ./main.out
- ^Cbegin delay handler...
- sleep 0 ...
- sleep 1 ...
- ^C
- zhaixue@ubuntu:~/DTLinux/0-11$
来修改一下 void delay_handler(int sig) 函数,在void delay_handler(int sig)函数中再一次调用 sysv_signal(SIGINT,delay_handler); 那么就相当于去掉OneShot特性。
- #define _GNU_SOURCE
- //#define _XOPEN_SOURCE 600
- //#define _POSIX_C_SOURCE 200800L
-
- #include
- #include
- #include
- #include
- #include
-
- void delay_handler(int sig)
- {
- int i = 0;
-
- sysv_signal(SIGINT,delay_handler);
-
- printf("begin delay handler...\n");
-
- for(i=0;i<5;i++)
- {
- printf("sleep %d ...\n",i);
- sleep(1);
- }
-
- printf("end delay handler...\n");
- }
-
- void signal_handler(int sig)
- {
- printf("handler : sig = %d\n",sig);
- }
-
- int main(void)
- {
- //signal(SIGINT,signal_handler);
- //signal(40,signal_handler);
- sysv_signal(SIGINT,delay_handler);
- //bsd_signal(SIGINT,signal_handler);
-
- while(1)
- {
- sleep(1);
- }
-
- return 0;
- }
编译运行:
- zhaixue@ubuntu:~/DTLinux/0-11$ gcc main.c -o main.out
- zhaixue@ubuntu:~/DTLinux/0-11$ ./main.out
- ^Cbegin delay handler...
- sleep 0 ...
- sleep 1 ...
- sleep 2 ...
- ^Cbegin delay handler...
- sleep 0 ...
- sleep 1 ...
- sleep 2 ...
- ^Cbegin delay handler...
- sleep 0 ...
- sleep 1 ...
- sleep 2 ...
- sleep 3 ...
- sleep 4 ...
- end delay handler...
- sleep 3 ...
- sleep 4 ...
- end delay handler...
- sleep 3 ...
- sleep 4 ...
- end delay handler...
- ^Cbegin delay handler...
- sleep 0 ...
- sleep 1 ...
- sleep 2 ...
- sleep 3 ...
- sleep 4 ...
- end delay handler...
- ^\Quit (core dumped)
- zhaixue@ubuntu:~/DTLinux/0-11$
可以看到OneShot特性相当于已经没有了。
接下来看 BSD风格的信号处理函数,会有什么样的结果。
main.c
- //#define _GNU_SOURCE
- #define _XOPEN_SOURCE 600
- #define _POSIX_C_SOURCE 200800L
-
- #include
- #include
- #include
- #include
- #include
-
- void delay_handler(int sig)
- {
- int i = 0;
-
- //sysv_signal(SIGINT,delay_handler);
-
- printf("begin delay handler...\n");
-
- for(i=0;i<5;i++)
- {
- printf("sleep %d ...\n",i);
- sleep(1);
- }
-
- printf("end delay handler...\n");
- }
-
- void signal_handler(int sig)
- {
- printf("handler : sig = %d\n",sig);
- }
-
- int main(void)
- {
- //signal(SIGINT,signal_handler);
- //signal(40,signal_handler);
- //sysv_signal(SIGINT,delay_handler);
- bsd_signal(SIGINT,delay_handler);
-
- while(1)
- {
- sleep(1);
- }
-
- return 0;
- }
- zhaixue@ubuntu:~/DTLinux/0-11$ gcc main.c -o main.out
- zhaixue@ubuntu:~/DTLinux/0-11$ ./main.out
- ^Cbegin delay handler...
- sleep 0 ...
- sleep 1 ...
- sleep 2 ...
- ^Csleep 3 ...
- sleep 4 ...
- end delay handler...
- begin delay handler...
- sleep 0 ...
- sleep 1 ...
- sleep 2 ...
- sleep 3 ...
- sleep 4 ...
- end delay handler...
- begin delay handler...
- sleep 0 ...
- ^Csleep 1 ...
- sleep 2 ...
- ^Csleep 3 ...
- sleep 4 ...
- end delay handler...
- begin delay handler...
- sleep 0 ...
- sleep 1 ...
- sleep 2 ...
- sleep 3 ...
- sleep 4 ...
- end delay handler...
- ^\Quit (core dumped)
- zhaixue@ubuntu:~/DTLinux/0-11$
可以看到不会发生重入,必须等待当前的信号处理函数处理完,才能够处理下一次的信号。当下一次信号来的时候,必须排队等着。
Linux 默认的 signal 信号处理函数 和 BSD风格的 bsd_signal(SIGINT,delay_handler) 信号处理函数是一致的。
main.c
- #define _GNU_SOURCE
- //#define _XOPEN_SOURCE 600
- //#define _POSIX_C_SOURCE 200800L
-
- #include
- #include
- #include
- #include
- #include
- #include
-
- void delay_handler(int sig)
- {
- int i = 0;
-
- //sysv_signal(SIGINT,delay_handler);
-
- printf("begin delay handler...\n");
-
- for(i=0;i<5;i++)
- {
- printf("sleep %d ...\n",i);
- sleep(1);
- }
-
- printf("end delay handler...\n");
- }
-
- void signal_handler(int sig)
- {
- printf("handler : sig = %d\n",sig);
- }
-
- int r_read(char* data,int len)
- {
- int ret = -1;
-
- while(data && ((ret = read(STDIN_FILENO,data,len-1)) == -1) && (errno == EINTR))
- {
- printf("restart syscall mannually...\n");
- }
-
- if(ret != -1)
- {
- data[ret] = 0;
- }
-
- return ret;
- }
-
- int main(void)
- {
- char buf[32]={0};
- //signal(SIGINT,delay_handler);
- //signal(40,signal_handler);
- sysv_signal(SIGINT,signal_handler);
- //bsd_signal(SIGINT,delay_handler);
-
- r_read(buf,32);
-
- printf("input: %s\n",buf);
-
- return 0;
- }
- zhaixue@ubuntu:~/DTLinux/0-11$ gcc main.c -o main.out
- zhaixue@ubuntu:~/DTLinux/0-11$ ./main.out
- 1234^Chandler : sig = 2
- restart syscall mannually...
- test
- input: test
-
- zhaixue@ubuntu:~/DTLinux/0-11$
可以看到 read 系统调用,被信号给中断了。
实验 BSD 风格的 signal 函数。
- //#define _GNU_SOURCE
- #define _XOPEN_SOURCE 600
- #define _POSIX_C_SOURCE 200800L
-
- #include
- #include
- #include
- #include
- #include
- #include
-
- void delay_handler(int sig)
- {
- int i = 0;
-
- //sysv_signal(SIGINT,delay_handler);
-
- printf("begin delay handler...\n");
-
- for(i=0;i<5;i++)
- {
- printf("sleep %d ...\n",i);
- sleep(1);
- }
-
- printf("end delay handler...\n");
- }
-
- void signal_handler(int sig)
- {
- printf("handler : sig = %d\n",sig);
- }
-
- int r_read(char* data,int len)
- {
- int ret = -1;
-
- while(data && ((ret = read(STDIN_FILENO,data,len-1)) == -1) && (errno == EINTR))
- {
- printf("restart syscall mannually...\n");
- }
-
- if(ret != -1)
- {
- data[ret] = 0;
- }
-
- return ret;
- }
-
- int main(void)
- {
- char buf[32]={0};
- //signal(SIGINT,signal_handler);
- //signal(40,signal_handler);
- //sysv_signal(SIGINT,signal_handler);
- bsd_signal(SIGINT,signal_handler);
-
- r_read(buf,32);
-
- printf("input: %s\n",buf);
-
- return 0;
- }
- zhaixue@ubuntu:~/DTLinux/0-11$ gcc main.c -o main.out
- zhaixue@ubuntu:~/DTLinux/0-11$ ./main.out
- 1234^Chandler : sig = 2
- ^Chandler : sig = 2
- ^Chandler : sig = 2
- ^\Quit (core dumped)
- zhaixue@ubuntu:~/DTLinux/0-11$
可以看到,BSD风格的 signal 函数会自动重启系统调用。和 sysv 风格的信号函数不一样,没有打印 restart syscall mannually... 出来。
默认风格的 signal 函数 和 BSD风格的 signal 函数一样,会自动重启系统调用。
问题:BSD风格的 signal 函数,处理A信号期间,如果收到B信号会发生什么?会不会重入?
main.c
- //#define _GNU_SOURCE
- #define _XOPEN_SOURCE 600
- #define _POSIX_C_SOURCE 200800L
-
- #include
- #include
- #include
- #include
- #include
- #include
-
- void delay_handler(int sig)
- {
- int i = 0;
-
- //sysv_signal(SIGINT,delay_handler);
-
- printf("begin delay handler...\n");
-
- for(i=0;i<5;i++)
- {
- printf("sleep %d ...\n",i);
- sleep(1);
- }
-
- printf("end delay handler...\n");
- }
-
- void signal_handler(int sig)
- {
- printf("handler : sig = %d\n",sig);
- }
-
- int r_read(char* data,int len)
- {
- int ret = -1;
-
- while(data && ((ret = read(STDIN_FILENO,data,len-1)) == -1) && (errno == EINTR))
- {
- printf("restart syscall mannually...\n");
- }
-
- if(ret != -1)
- {
- data[ret] = 0;
- }
-
- return ret;
- }
-
- int main(void)
- {
- char buf[32]={0};
- //signal(SIGINT,signal_handler);
- bsd_signal(40,signal_handler);
- //sysv_signal(SIGINT,signal_handler);
- bsd_signal(SIGINT,delay_handler);
-
- r_read(buf,32);
-
- printf("input: %s\n",buf);
-
- return 0;
- }
test.c
- #include
- #include
- #include
- #include
- #include
-
- int main(int argc,char* argv[])
- {
- int pid = atoi(argv[1]);
- int sig = atoi(argv[2]);
-
- printf("send sig(%d) to process(%d)...\n",sig,pid);
-
- kill(pid,sig); //send signal
-
- raise(SIGINT); //end execute
-
- while(1)
- {
- printf("while...\n");
- sleep(1);
- }
-
- return 0;
- }
- zhaixue@ubuntu:~/DTLinux/0-11$ gcc main.c -o main.out
- zhaixue@ubuntu:~/DTLinux/0-11$ ./main.out
- ^Cbegin delay handler...
- sleep 0 ...
- sleep 1 ...
- sleep 2 ...
- handler : sig = 40
- sleep 3 ...
- sleep 4 ...
- end delay handler...
- ^Cbegin delay handler...
- sleep 0 ...
- sleep 1 ...
- sleep 2 ...
- sleep 3 ...
- sleep 4 ...
- end delay handler...
- ^\Quit (core dumped)
- zhaixue@ubuntu:~/DTLinux/0-11$
- zhaixue@ubuntu:~/DTLinux/0-11$ gcc test.c -o test.out
- zhaixue@ubuntu:~/DTLinux/0-11$ ps -ajx | grep main.out
- 8966 11517 11517 8966 pts/0 11517 S+ 1000 0:00 ./main.out
- 11392 11524 11523 11392 pts/1 11523 S+ 1000 0:00 grep --color=auto main.out
- zhaixue@ubuntu:~/DTLinux/0-11$ ./test.out 11517 40
- send sig(40) to process(11517)...
-
- zhaixue@ubuntu:~/DTLinux/0-11$
问题:BSD风格的 signal 函数,处理A信号期间,如果收到B信号会发生什么?会不会重入?
会立即马上的处理B信号,处理完B信号之后,马上返回处理A信号。
-并非所有的系统调用对信号中断都表现同样的行为
一些系统调用支持信号中断后自动重启
read()、write()、wait()、waitpid()、ioctl() ...
一些系统调用完全不支持中断后自动重启
poll()、select()、usleep()、...
函数 | OneShot | 屏蔽自身 | 重启系统调用 |
signal(...) | false | true | true |
sysv_signal(...) | yes | false | false |
bsd_signal(...) | false | true | true |
在信号处理上,Linux系统更接近 BSD风格的操作;默认的signal函数在不同的 Linux发行版上语义可能不同,从代码移植行角度,避免直接使用 signal(...)函数。
- /* Get and/or set the action for signal SIG. */
-
- extern int sigaction (
-
- int __sig,
-
- const struct sigaction *__restrict __act,
-
- struct sigaction *__restrict __oact) __THROW;
int __sig :自定义处理那个信号
const struct sigaction *__restrict __act :信号的处理方式
struct sigaction *__restrict __oact :原有的信号处理方式,通常情况下为 NULL
- /* Structure describing the action to be taken when a signal arrives. */
- struct sigaction
- {
- /* Signal handler. */
- #if defined __USE_POSIX199309 || defined __USE_XOPEN_EXTENDED
- union
- {
- /* Used if SA_SIGINFO is not set. */
- __sighandler_t sa_handler;
- /* Used if SA_SIGINFO is set. */
- void (*sa_sigaction) (int, siginfo_t *, void *);
- }
- __sigaction_handler;
- # define sa_handler __sigaction_handler.sa_handler
- # define sa_sigaction __sigaction_handler.sa_sigaction
- #else
- __sighandler_t sa_handler;
- #endif
-
- /* Additional set of signals to be blocked. */
- __sigset_t sa_mask;
-
- /* Special flags. */
- int sa_flags;
-
- /* Restore handler. */
- void (*sa_restorer) (void);
- };
sigset_t sa_mask;
信号屏蔽:sa_mask = SIGHUP | SIGINT | SIGUSR1;
注意: 并不是所有的信号都 可以被屏蔽,如:SIGKILL、SIGSTOP
先来看一个问题:基于信号发送的进程间通信方式可靠吗???
可以看到 Linux一共支持 64种类型的信号,但是有个奇怪的现象就是:
4.1 查询信号队列上限 :ulimit -i
4.2 设置信号队列上限 :ulimit -i 10000
目标:验证信号可靠性(不可靠信号 or 可靠信号)
方案:对目标进程“疯狂”发送N次信号,验证信号处理函数调用次数
预备函数:
int sigaddset(sigset_t* set,int signum);
int sigdelset(sigset_t* set,int signum);
int sigfillset(sigset_t* set);
int sigemptyset(sigset_t* set);
int sigprocmask(int how,const sigset_t* set,sigset_t* oldset);
4.1 严格意义上,没有明确规定优先级
4.2 实际上,Linux优先递送不可靠信号
5. 多个 不可靠信号 同时未决,优先递送谁?
优先递送硬件相关信号
SIGSEGV、SIGBUS、SIGILL、SIGTRAP、SIGFPE、SIGSYS
6. 优先递送信号值小的不可靠信号
7. 不可靠信号 优先于 可靠信号 递送
程序能正确且无意外的按照预期方式执行。
什么时候信号递达是不确定的 --> 主程序被中断的位置是不确定的
不可重入函数:函数不能由超过一个任务共享,除非能确保函数的互斥(或者使用信号量,或者在代码的关键部分禁用中断)