目录
1.如何发送信号给另外一个进程? -> kill() -> man 2 kill
2.如何捕捉信号? -> signal() -> man 2 signal
2.例题1: 写一个程序,先清空信号集,再把SIGUSR1加入到集合中,判断信号是不是在集合中。
七、如何设置信号集为阻塞状态? -> sigprocmask() -> man 2 sigprocmask
一、进程之间的通信 -- 信号
1.什么是信号
信号是一种异步通信机制,一般情况下,进程什么时候会收到信号、收到什么信号是无法事先预料的(就像你家的门铃,你不知道它什么时候会响,但是门铃响的时候我们可以下楼开门(处理))
2.在linux下,有哪些信号
gec@ubuntu:/mnt/hgfs/GZ22229/09系统编程/03/1-code$ 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
例如:
19) SIGSTOP //signal 信号
信号值)SIG+信号名字
其实信号的名字与信号值是等价的,它们是宏定义来的,被定义在一个头文件:
/usr/include/asm-generic/signal.h
#define SIGHUP 1
#define SIGINT 2
#define SIGQUIT 3
#define SIGILL 4
3.在linux下,这些信号究竟是由谁来发出?
1)由系统来发出。
14) SIGALRM -> 当在程序中调用alarm()时,如果到点了,就会自动发出这个信号。
17) SIGCHLD -> 当子进程退出时,自动发出这个信号给父进程。SIGCHLD = signal child
2)信号也可以由用户来发送。
如果是由用户来发送,则需要学习 kill / killall 这两个命令。
4.用户如何发送信号给进程?
方法一:
1)首先查看目标进程的PID号。 -> ps -ef(或者使用getpid打印自己的进程id号)
PID号
gec 4630 4310 0 00:30 pts/4 00:00:00 ./a.out
2)通过kill命令发送9号信号给该进程,杀死进程。(kill -9 杀死进程这个指令很常用)
kill -9 4630
kill -SIGKILL 4630 或者 kill -KILL 4630
说明:kill是给pid值发送信号
方法二:
直接通过killall命令给进程名字发送信号
killall -9 a.out
killall -SIGKILL a.out 或者 killall -KILL a.out -> 只要名字为a.out,都会收到这个信号。
说明:killall是给进程名发送信号
练习1:
写一个进程fork之后,父进程一直执行,子进程也一直执行,分别用kill和killall干掉他们。
#include <stdio.h>
#include <unistd.h>
int main(int argc,char **argv)
{
pid_t id = fork();
if(id == -1)
{
perror("fork fail");
return -1;
}
else if(id > 0)
{
while(1)
{
//\n的重要性 刷新缓冲区
printf("[%d]我走上路\n",getpid());
sleep(1);
}
}
else if(id == 0)
{
while(1)
{
printf("[%d]我走中路\n",getpid());
sleep(1);
}
}
return 0;
}
二、关于信号的函数接口
1.如何发送信号给另外一个进程? -> kill() -> man 2 kill
#include <sys/types.h>
#include <signal.h> -> linux信号的专属头文件
int kill(pid_t pid, int sig);
函数作用:
向指定进程或者进程组,发送一个指定的信号
参数:
pid:进程号
sig:信号值
例子
#include<stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <stdlib.h>
int main(int argc, char*argv[]) // ./a.out 3445
{
//获取你要发送的信号的进程的ID号
int id = atoi(argv[1]);
//发送信号
kill(id,SIGINT);
return 0;
}
2.如何捕捉信号? -> signal() -> man 2 signal
#include <signal.h>
typedef void (*sighandler_t)(int); //函数指针
sighandler_t signal(int signum, sighandler_t handler);
函数作用:
捕捉一个指定的信号,即预先为某信号的到来做好准备
参数:
signum 需要捕捉的信号
handler
SIG_IGN 忽略该信号
SIG_DFL 执行该信号的默认动作
void (*p)(int) 执行由 p 指向的信号响应函数
返回值:
成功返回 最近一次调用该函数时第二个参数的值
失败返回 SIG_ERR (#define SIG_ERR -1)
注意:
>1.所谓的捕捉信号就是获取当这个信号来之后,去执行信号响应函数,原本的信号默认动作就不会执行了。
>2.当调用signal函数之后 ,程序不会阻塞,而是往下面代码执行,但是这个捕捉设置是全局有效
>3.SIGKILL 、SIGSTOP 不能被捕捉,只能执行默认的动作
例子:
#include<stdio.h>
#include <sys/types.h>
#include <signal.h>
//信号响应函数 ,也就是说signal捕捉到指定的信号之后,去执行这个函数
void signalHandle(int arg)
{
printf("arg:%d\n",arg);
printf("signalHandle 听说你想杀死我\n");
}
int main(int argc, char*argv[]) // ./a.out 3445
{
//捕捉信号SIGINT,去执行信号响应函数
signal(SIGINT,signalHandle);
while(1);
return 0;
}
说明:函数名本身就是指针