C语言笔记-22-Linux基础-信号
文章目录
前言
自学笔记,没有历史知识铺垫(省略百度部分)C语言笔记-22-Linux基础-信号
一、信号概括
软件中的中断信号,软中断、异常中断都是信号,中断机制,信号处理程序。
系统提供的中断信号
linux 64个,数量根据系统不同。此处展示mac中断信号
No Name Default Action Description
1 SIGHUP terminate process terminal line hangup
2 SIGINT terminate process interrupt program
3 SIGQUIT create core image quit program
4 SIGILL create core image illegal instruction
5 SIGTRAP create core image trace trap
6 SIGABRT create core image abort program (formerly SIGIOT)
7 SIGEMT create core image emulate instruction executed
8 SIGFPE create core image floating-point exception
9 SIGKILL terminate process kill program
10 SIGBUS create core image bus error
11 SIGSEGV create core image segmentation violation
12 SIGSYS create core image non-existent system call invoked
13 SIGPIPE terminate process write on a pipe with no reader
14 SIGALRM terminate process real-time timer expired
15 SIGTERM terminate process software termination signal
16 SIGURG discard signal urgent condition present on socket
17 SIGSTOP stop process stop (cannot be caught or ignored)
18 SIGTSTP stop process stop signal generated from keyboard
19 SIGCONT discard signal continue after stop
20 SIGCHLD discard signal child status has changed
21 SIGTTIN stop process background read attempted from control terminal
22 SIGTTOU stop process background write attempted to control terminal
23 SIGIO discard signal I/O is possible on a descriptor (see fcntl(2))
24 SIGXCPU terminate process cpu time limit exceeded (see setrlimit(2))
25 SIGXFSZ terminate process file size limit exceeded (see setrlimit(2))
26 SIGVTALRM terminate process virtual time alarm (see setitimer(2))
27 SIGPROF terminate process profiling timer alarm (see setitimer(2))
28 SIGWINCH discard signal Window size change
29 SIGINFO discard signal status request from keyboard
30 SIGUSR1 terminate process User defined signal 1
31 SIGUSR2 terminate process User defined signal 2
信号的产生 > 信号的到达 > 信号的处理
- 未决信号:信号产生到处理的过程中,信号处于未决状态(未处理状态)
信号处理三种方法
SIG_IGN
缺省处理 (大部分进程的缺省处理,都是终止当前进程,即信号2)SIG_DFL
忽略处理- 用户自定义处理
二、信号函数
typedef void (*sig_t) (int);
改变进程的信号处理函数
sig_t signal(int sig, sig_t func);
入参
- sig 信号编号
- func 指定信号处理函数指针
返回值
错误:SIG_ERR errno被设置
成功:返回原来的信号处理函数指针
代码示例
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
signal(SIGINT, SIG_IGN);
sleep(10);
return 0;
}
// 执行结果 ctrl+c中断时,将无法生效
dony15$ ./main
^C^C^C^C^C^C^C^C^C^C^C^C^C^C
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void customHandle(int sig)
{
printf("自定义函数执行%d\n", sig);
return;
}
int main(int argc, char *argv[])
{
signal(SIGINT, customHandle);
sleep(10);
return 0;
}
// ctrl+c中断时 执行结果
dony15$ ./main
^C自定义函数执行2
// 终端使用kill发送信号时 执行结果 kill -2 16817
自定义函数执行2
三、信号的产生
- 硬件产生信号:
ctrl+c
ctrl+\
- 使用命令给进程发信号:
kill -信号编号 进程pid
- 使用系统调用或库函数,向进程发送信号:
3.1.kill()
给指定进程发送指定信号
3.2.raise()
给当前进程发送信号
3.3.alarm()
定时发送信号
3.4.abort()
给自己发送异常终止信号
3.5.setitimer()
设置定时器(闹钟)。可代替alarm函数。精度微妙us,可以实现周期定时。
alarm定时发送信号示例
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
alarm(1);
for (int i = 0; i>=0; i++)
{
printf("i=%d \n",i);
}
return 0;
}
// 执行结果
i=0
i=1
i=2
...
i=7031440
i=7031441
pause 阻塞线程
让当前进程、线程阻塞,等待信号,执行完信号处理函数后返回。
int pause(void);
固定返回 -1 errno被设置
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void customHandle(int sig)
{
printf("自定义函数执行%d\n", sig);
return;
}
int main(int argc, char *argv[])
{
signal(SIGINT, customHandle);
int result= pause();
perror("pause");
return 0;
}
// 终端使用kill发送信号时 执行结果 kill -2 4687
pause: Interrupted system call
自定义函数执行2
四、信号掩码集和未决信号集
PCB中以数组形式,
bit
元素记录信号掩码集
和未决信号集
,数组下标长度对应信号编码 如arr[0]
对应SIGHUP
- 信号掩码集: 记录信号是否被阻塞,元素为1时,表示该下标对应信号被阻塞,0时标识未阻塞
- 未决信号集:记录信号是否未决,元素为1时,表示该下标对应信号未决,0时标识没有信号产生
- 同一数组下标(同一信号),掩码集=1 表示信号阻塞。此时对应数组下标的未决信号无论是0还是1,都无法执行。
- 同一数组下标(同一信号),掩码集=0 表示信号不阻塞。此时对应数组下标的未决信号=1时,表示信号到达即可执行。
- 同一数组下标(同一信号),掩码集=0 表示信号不阻塞。此时对应数组下标的未决信号=0时,表示没有信号。
五、设置阻塞信号
信号集类型相关操作
#include <signal.h>
// sigset_t 信号集类型
// 将传入的信号集初始化为空 0 sig empty set(set表示集,非设置的意思)。成功返回0 失败 -1 errorno
int sigemptyset(sigset_t *set);
// 将传入的信号集初始化为填满状态 1 sig fill set。 成功返回0 失败 -1 errorno
int sigfillset(sigset_t *set);
// 将信号添加到信号集中 sig add set。 成功返回0 失败 -1 errorno
int sigaddset(sigset_t *set, int signo);
// 将信号从信号集中移除 sig del set。 成功返回0 失败 -1 errorno
int sigdelset(sigset_t *set, int signo);
// 判断信号是否为信号集中的成员 sig is member。 真1 假0
int sigismember(const sigset_t *set, int signo);
示例代码
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int main(int argc, char *argv[])
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, 1);
sigaddset(&set, 2);
int isMember = sigismember(&set, 2);
isMember ? printf("Y\n") : printf("N\n");
sigdelset(&set, 2);
int isMember2 = sigismember(&set, 2);
isMember2 ? printf("Y\n") : printf("N\n");
return 0;
}
// 输出结果
Y
N
设置信号集到信号掩码集
// SIG_BLOCK 将传入信号集与原有信号集的并集,更新到信号掩码集。
// SIG_UNBLOCK 将传入信号集从原有信号集排除,更新到信号掩码集。
// SIG_SETMASK 保存传入信号集到信号掩码集,并覆盖与原有信号集交集部分。
// oset 原信号掩码集,NULL 丢弃原信号掩码集。
int sigprocmask(int how, const sigset_t *restrict set, sigset_t *restrict oset);
// 返回 0成功 -1失败 errorno
示例代码
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int main(int argc, char *argv[])
{
sigset_t set;
sigemptyset(&set);
// 阻塞2号信号
sigaddset(&set, 2);
sigprocmask(SIG_SETMASK, &set, NULL);
while (1);
printf("end\n");
return 0;
}
// 输出结果 尝试ctrl+c 触发2号信号,由于设置2号信号在信号掩码中阻塞,此时失效,尝试使用3号信号ctrl+$结束程序
dony15$ ./a.out
^C^C^C^C^C^C^C^C^C^\Quit: 3
六、获取未决信号
总结
本章主要为C语言笔记-22-Linux基础-信号