进程间通信常见方式-信号
文章目录
学习目标:
熟练使用信号捕捉函数signal。
熟练使用信号捕捉函数sigaction
熟练掌握使用信号完成子进程的回收
信号:
信号的特质:信号是软件层面上的“中断”,一旦信号产生,无论程序执行到什么位置,必须立即停止运行,处理信号,处理结束,再继续执行后续指令。
信号的相关概念:
- 按键产生
- 系统调用产生
- 软件条件产生
- 硬件异常产生
- 命令产生
概念:
- 未决:产生与递达之间的状态。
- 递达:产生并且送达到进程,直接被内核处理。
- 信号处理方式:执行默认处理动作、忽略、捕捉(自定义)。
- 阻塞信号集(信号屏蔽字),本质:位图,用来记录信号的屏蔽状态。一旦被屏蔽的信号,再解除屏蔽之前,一直处于未决态。
- 未决信号集,本质:位图,用来记录信号的处理状态。该信号集中的信号,表示已经产生,但未被处理。
信号4要素:
- 信号使用之前,应先确定四要素,而后再用
- 编号、名称、对应事件、默认处理动作。
信号的编号:信号定义在signal.h头文件中。
如下:
kill命令和kill函数:
kill命令:kill命令用来给某个进程发送信号。
kill [options] <pid> [...]
kill函数:给指定进程发送指定信号。
int kill(pid_t pid,int signum);
参数
pid:
> 0:发送信号给指定进程。
= 0:发送信号给调用kill函数的那个进程处于同一进程组的进程。
< -1:取绝对值,发送信号给该绝对值所对应的进程组的所有成员。
= -1:发送信号给有权限发送的所有进程。
signum:代发送的信号
返回值
成功:0
失败:-1,设置相应的errno
alarm函数:
alarm函数:在进程中设置一个定时器,当定时器指定的时间到时,它向进程发送SIGALRM信号。设置忽略或不捕捉该信号,如果采用默认方式其动作是终止该调用该alarm函数的进程。(使用自然计时法)
unsigned int alarm(unsigned int seconds);
参数
seconds:定时秒数
返回值
成功: 上次定时剩余时间。
无错误现象
alarm(0);取消闹钟
time命令:查看程序执行时间。实际时间 = 用户时间 + 内核时间 + 等待时间
setitimer函数:
setitimer函数:实现精度较高的定时功能。
int setitimer(int which,const struct itimerval *new_value,struct itimerval *old_value);
参数
which:
ITIMER_REAL:采用自然计时(SIGALRM)
ITIMER_VIRTUAL:采用用户空间计时(SIGVTALRM)。
ITIMER_PROF:采用内核 + 用户空间计时(SIGPROF)。
new_value:定时秒数 。
old_value:传出参数:上次定时剩余时间。
返回值
成功:0
失败:-1,设置相应的errno
struct itimerval 类型:
struct itimerval{
struct timeval it_interval; //周期定时秒数
struct timeval it_value; //第一次定时描述
}
struct timeval类型:
struct timeval{
time_t tv_sec; //秒
suseconds_t tv_usec;//微秒
}
time命令:查看程序执行时间。实际时间 = 用户时间 + 内核时间 + 等待时间
信号集操作函数:
sigset_t set;//自定义信号集
sigemptyset(sigset_t *set);//清空信号集
sigfillset(sigset_t *set);//全部置1
sigaddset(sigset_t *set,int signum);//将一个信号添加到集合中
sigdelset(sigset_t *set,int signum);//将一个信号从集合中移除
sigismember(sigset_t *set,int signum);//判断一个信号是否在集合中。(在 1, 不在 0)
sigprocmask函数:
sigprocmask函数:用于改变进程的当前阻塞信号集,也可以用来检测当前进程的信号掩码。
int sigprocmask(int how,const sigset_t *set,struct sigset_t *oldset);
参数
how:
SIG_BLOCK:设置阻塞
SIG_UNBLOCK:取消阻塞。
SIG_SETMASK:用自定义set替换mask。
set:自定义set。
oldset:旧的maskt。
返回值
成功:0
失败:-1,设置相应的errno
sigpending函数:
sigpending函数:返回在送往进程的时候被阻塞挂起的信号集。
int sigpending(sigset_t *set);
参数
set:传出的未决信号集。
返回值
成功:0
失败:-1,设置相应的errno
signal函数:
signal函数:组测一个信号捕捉函数。
typedef void(*sighandler_t)(int);
sighandler_t signal(int signum,sighandler_t handler);
参数
signum:待发送的信号。
handler:处理的方式。
返回值
成功:该函数返回信号处理程序之前的值。
失败:SIG_ERR
sigaction函数:
sigaction函数:查询或设置信号处理方式。
int sigaction(int signum,const struct sigaction *act,struct *oldact);
参数
signum:待发送的信号。
act:传入参数,新的处理方式。
oldact:传出参数,旧的处理方式。
返回值
成功:0
失败:-1,设置相应的errno
struct sigaction 类型:
struct sigaction{
void (*sa_handler)(int); //新的信号处理函数
void (*sa_sigaction)(int,siginfo_t*,void *);
sigset_t sa_mask;//用来设置处理该信号时暂时将sa_mask指定的信号集搁置
int sa_flags;//用来设置信号处理的其他相关操作,下列的数值可用。
/***********************************************
SA_RESETHAND:当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL
SA_RESTART:如果信号中断了进程的某个系统调用,则系统自动启动该系统调用
SA_NODEFER:一般情况,当信号处理函数运行时,内核将阻塞该给定信号。但是如果设置了SA_NODEFER标记,那么在该信号处理函数运行时,内核将不会处理阻塞该信号。
***********************************************/
void (*sa_restorer)(void);//此参数没有使用
}
信号捕捉特性:
- 捕捉函数执行期间,信号屏蔽字,有mask–>sa_mask,捕捉函数执行结束,恢复回mask
- 捕捉函数执行期间,本信号自动被屏蔽(sa_flags = 0)
- 捕捉函数执行期间,被屏蔽信号多次发送,接触屏蔽后只处理一次!
中断系统调用:
系统调用可分为两类,慢速系统调用和其他系统调用
- 慢速系统调用,可能会使进程永远阻塞的一类,如果在阻塞期间收到一个信号,该系统调用就被中断,不再继续执行(早期),也可以设定系统调用是否重启。如:read、write、pause、wait…
- 其他系统调用:getpid、getppid、fork…
慢速系统调用被中断的相关行为,实际上就是pause行为。如:read
- 想中断pause,信号不能被屏蔽
- 信号处理方式必须是捕捉(默认、忽略都不行)
- 中断后返回-1,设置errno为EINTR(表示被信号中断)可修改sa_flags参数来设置被信号中断后系统调用是否重启。SA_INTERRURT不重启,SA_RESTART重启。
- sa_flags还有很多可选参数,适用于不同情况。如:捕捉信号后,在执行函数期间,不希望自动阻塞该信号,可将sa_flags设置为SA_NODEFER,除非sa_mask中包含该信号。
补充:
信号捕捉
sighandler_t signal(int signum,sighandler_t handler);
参数
set:传出的未决信号集。
返回值
成功:0
失败:-1,设置相应的errno
发信号函数
int raise(int sig);
void abort(void);
内核实现信号捕捉过程:
SIGCHLD信号产生条件:
- 子进程终止时
- 子进程接收到SIGSTOP信号停止时
- 子进程处于停止态,接收到SIGCONT后唤醒时
信号表:
取值 | 名称 | 解释 | 默认动作 |
---|---|---|---|
1 | SIGHUP | 挂起 | |
2 | SIGINT | 中断 | |
3 | SIGQUIT | 退出 | |
4 | SIGILL | 非法指令 | |
5 | SIGTARP | 断点或陷阱指令 | |
6 | SIGABRT | abort发出的信号 | |
7 | SIGBUS | 非法内存访问 | |
8 | SIGFPE | 浮点异常 | |
9 | SIGKILL | kill信号 | 不能被忽略、处理和阻塞 |
10 | SIGUSR1 | 用户信号1 | |
11 | SIGSEGV | 无效内存访问 | |
12 | SIGUSR2 | 用户信号2 | |
13 | SIGPIPE | 管道破损,没有读端的管道写数据 | |
14 | SIGALRM | alarm发出的信号 | |
15 | SIGTERM | 终止信号 | |
16 | SIGSTKFLT | 栈溢出 | |
17 | SIGCHLD | 子进程退出 | 默认忽略 |
18 | SIGCONT | 进程继续 | |
19 | SIGSTOP | 进程停止 | 不能被忽略、处理和阻塞 |
20 | SIGSTP | 进程停止 | |
21 | SIGTTIN | 进程停止,后台进程从终端读数据时 | |
22 | SIGTTOU | 进程停止,后台进程想从终端写数据时 | |
23 | SIGURG | I/O有紧急数据到达当前进程 | 默认忽略 |
24 | SIGXCPU | 进程的CPU时间片到期 | |
25 | SIGXFSZ | 文件大小的超出上限 | |
26 | SIGVTALRM | 虚拟时钟超时 | |
27 | SIGPROF | profile时钟超时 | |
28 | SIGWINCH | 窗口大小改变 | 默认忽略 |
29 | SIGIO | I/O相关 | |
30 | SIGPWR | 关机 | 默认忽略 |
31 | SIGSYS | 系统调用异常 |