
Linux信号
7.1 修改
7.2 实现自定义的
发布日期:2021-05-08 23:07:56
浏览次数:20
分类:精选文章
本文共 2972 字,大约阅读时间需要 9 分钟。
Linux信号机制详解
1. 信号的概念及机制
信号在计算机科学中扮演着重要角色,就像人类社会中的信息传递一样。Linux系统中的信号用于通知进程某些事件发生,进程接收到信号后会暂停当前执行任务,处理信号,等处理完毕后再继续执行。信号的核心特征包括四个要素:信号编号、信号名、产生事件以及默认处理动作。
2. 信号的产生与处理方式
信号可以通过多种方式产生,主要有以下几种:
- 按键产生:如
Ctrl+c
、Ctrl+z
,这些组合键常用于终止进程。 - 系统调用产生:如
kill
、raise
、abort
,这些函数用于强制终止进程。 - 硬件异常产生:如段错误、除零错误、总线错误等,这些错误会触发相应的信号。
- 软件条件产生:如定时器超时(
alarm
函数)。 - 命令产生:如shell中的
kill
命令。
信号的处理方式主要有三种:
- 执行默认动作:如终止进程、生成核心文件等。
- 忽略信号:不采取任何特殊处理。
- 捕获并执行自定义操作:通过注册信号处理函数来实现。
需要注意的是,SIGKILL
和SIGSTOP
信号无法被捕捉、阻塞或忽略,只能执行默认动作。
3. 内核处理信号的机制
信号的产生和处理主要由内核完成。当内核检测到某个信号被触发时,并不会立即处理,而是在用户模式返回时(如系统调用、中断或异常返回)才会进行处理。这种机制确保了信号处理的正确性和稳定性。
4. 信号的编号
在Linux系统中,信号编号从1
到31
,其中1~31
为普通信号,32~63
为实时信号(主要用于硬件驱动编程)。可以通过kill -l
命令查看系统支持的所有信号。
5. 信号的默认动作
信号的默认动作根据具体信号类型有所不同,常见的有:
SIGTERM
:终止进程。SIGCORE
:终止进程并生成核心文件。SIGIGNORE
:忽略信号。SIGCONT
:继续执行进程。SIGSTOP
:暂停进程。
通过man 7 signal
命令可以查看各信号的详细描述。
6. Linux系统提供的信号操作函数
6.1 信号的产生
可以通过kill
函数向指定进程发送指定信号。函数原型如下:
int kill(pid_t pid, int sig);
其中sig
为信号名,需使用宏定义,如SIGKILL
。
6.2 信号捕捉
- 注册信号捕捉函数:
typedef void (*sighandler_t)(int);sighandler_t signal(int signum, sighandler_t handler);
- 更健壮的接口:
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
结构体
struct sigaction
包含以下成员:sa_handler
:信号捕捉后的处理函数。sa_mask
:屏蔽信号集。sa_flags
:信号处理标志。
6.3 信号集操作
进程控制块维护两个信号集:阻塞信号集和未决信号集。可以通过以下函数进行操作:
- 初始化与清空信号集:
int sigemptyset(sigset_t *set);int sigfillset(sigset_t *set);
- 信号集操作:
int sigaddset(sigset_t *set, int signum);int sigdelset(sigset_t *set, int signum);int sigismember(const sigset_t *set, int signum);
- 设置与解除信号屏蔽:
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
- 读取未决信号集:
int sigpending(sigset_t *set);
- 替换屏蔽信号集并挂起进程:
int sigsuspend(const sigset_t *sigmask);
6.4 捕捉默认信号处理
通过修改默认信号处理函数,可以改变信号的行为。例如,捕捉SIGINT
信号并打印进程ID。
7. 信号接口函数测试
7.1 修改SIGINT
默认动作
#include#include #include void sigint_handler(int sig) { printf("Current Process Id = %d\n", getpid());}int main(int argc, char **argv) { signal(SIGINT, sigint_handler); while (1) { sleep(10); } return 0;}
运行此程序时,按下Ctrl+c
组合键,程序不会终止,而是打印当前进程ID。
7.2 实现自定义的mysleep
函数
#include#include #include void sig_alrm(int signo) { /* nothing to do */}unsigned int mysleep(unsigned int nsecs) { struct sigaction newact, oldact; sigset_t newmask, oldmask, suspmask; unsigned int unslept; newact.sa_handler = sig_alrm; sigemptyset(&newact.sa_mask); newact.sa_flags = 0; sigaction(SIGALRM, &newact, &oldact); sigemptyset(&newmask); sigaddset(&newmask, SIGALRM); sigprocmask(SIG_BLOCK, &newmask, &oldmask); alarm(nsecs); suspmask = oldmask; sigdelset(&suspmask, SIGALRM); sigsuspend(&suspmask); unslept = alarm(0); sigaction(SIGALRM, &oldact, NULL); sigprocmask(SIG_SETMASK, &oldmask, NULL); return unslept;}int main(void) { while (1) { mysleep(2); printf("Two seconds passed\n"); } return 0;}
通过mysleep
函数,可以实现自定义的睡眠功能,忽略SIGALRM
信号,默认动作为终止进程。
发表评论
最新留言
感谢大佬
[***.8.128.20]2025年05月08日 21时05分38秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
Linux——gcc编译器
2023-02-02
Linux——利用命名管道创建进程池
2023-02-02
Linux——匿名管道
2023-02-02
Linux——命令行参数及环境变量
2023-02-02
Linux——命名管道
2023-02-02
Linux——基本指令
2023-02-02
Linux——基础入门(1)
2023-02-02
Linux——基础入门(2)
2023-02-02
Linux——文件的系统调用
2023-02-02
Linux——磁盘和文件系统(一)
2023-02-02
Linux——缓冲区与FLIE*的原理简单实现
2023-02-02
Linux——进程地址空间
2023-02-02
Linux——进程池
2023-02-02
Linux——静态库
2023-02-02
Linux、Linux操作系统、GUN、GPL
2023-02-02
Linux、Windows渗透测试靶场手动搭建实战(附靶场安装包与安装脚本)
2023-02-02
linux一切皆文件之Unix domain socket描述符(二)
2023-02-02
linux上修改容器网卡docker0为固定ip
2023-02-02
Linux上压缩目录以及目录下的所有文件
2023-02-02
Linux上安装TeamViewer
2023-02-02