Linux 信号(signal)

  • 信号是 UNIX 和 Linux 系统响应某些条件而产生的一个事件。接收到该信号的进程会相应的采取一些行动。我们用术语 生成 表示一个信号的产生,使用术语 捕获 表示接收到一个信号。
  • 信号是由于某些错误条件而生成的,如 内存段冲突 / 浮点处理器错误 或 非法指令等。它们由 shell 和终端处理器生成来引起中断,它们还可以作为在 进程间传递消息修改行为 的一种方式,明确地由一个进程发送给另一个进程
目录
  1. 信号列表
  2. 处理信号(使用 signal 函数
  3. 发送信号(使用键盘组合键 / 使用 kill 命令 / 使用 kill 函数)
  4. 处理信号(使用 sigaction 函数)(优先使用该函数)

1. 信号列表
信号名称说明
SIGABORT* 进程异常终止
SIGALRM超时警告
SIGFPE* 浮点运行异常
SIGHUP连接挂断
SIGILL* 非法指令
SIGINT终端中断
SIGKILL终止进程(此信号不能被捕获或忽略
SIGPIPE向无读进程的管道写数据
SIGQUIT终端退出
SIGSEGV* 无效内存段访问
SIGTERM终止
SIGUSR1用户定义信号 1
SIGUSR2用户定义信号 2
SIGCHLD子进程已经停止或退出
SIGCONT继续执行暂停进程
SIGSTOP停止执行(此信号不能被捕获或忽略
SIGTSTP终端挂起
SIGTTIN后台进程尝试读操作
SIGTTOU后台进程尝试写操作

(‘ * ’ 表示:系统对信号的响应视具体实现而定)


2. 处理信号(使用 signal 函数)
  1. signal 函数
#include <signal.h>
void (*signal(int sig, void (*func)(int)))(int);
  1. 特殊的信号处理函数
名称说明
SIG_IGN忽略信号
SIG_DEL恢复默认行为
  1. 实验代码如下(程序响应 SIGINT 终端中断信号,然后恢复到该信号的默认行为):
/* test2.c */
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <stdio.h>

void handleSig(int);

void main(){
    printf("running...\n");
    signal(SIGINT, handleSig);

	// 主进程循环,等待信号
    while(1){
        sleep(2);
        printf("alive.\n");
    }
}

void handleSig(int sig){
    printf("got signal: %d\n", sig);
    signal(SIGINT, SIG_DFL);
}

运行程序,执行结果如下:

ubuntu@cuname:~/dev/beginning-linux-programming/test$ gcc -o test2 test2.c
ubuntu@cuname:~/dev/beginning-linux-programming/test$ ./test2
running...
alive.
alive.
^Cgot signal: 2 		// 第一次 响应 SIGINT 终端中断信号:打印字符串
alive.
alive.
^C						// 第二次 响应,程序默认终止
ubuntu@cuname:~/dev/beginning-linux-programming/test$

3. 发送信号(使用键盘组合键 / 使用 kill 命令 / 使用 kill 函数)
  1. 使用 kill 命令发送信号(格式为:‘kill 信号代码或信号名称 目标进程PID’)
ubuntu@cuname:~/dev$ kill -sigint 38897
  1. kill 函数(这个函数和同名的 kill 命令完成相同的功能
  • 想要发送一个信号,发送进程必须拥有相应的权限。这通常意味着两个进程必须拥有相同的用户 ID (即你只能发送信号给属于自己的进程,但超级用户可以发送信号给任何进程)
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
  1. alarm 函数(闹钟功能)
  • alarm 函数用来在 seconds 秒之后安排发送一个 SIGALRM 信号。但由于处理的延时和时间调度的不确定性,实际闹钟时间将比预先安排的要稍微拖后一点儿。
  • 把参数 seconds 设置为 0 将取消所有已设置的闹钟请求。
  • 如果在接收到 SIGALRM 信号之前再次调用 alarm 函数,则闹钟重新开始计时。
  • 每个进程只能有一个闹钟时间
#include <unistd.h>
unsigned int alarm(unsigned int seconds);

使用 alarm 函数,实现进程自我唤醒,代码如下:

#include <stdio.h>
#include <unistd.h>
#include <signal.h>

void handleSig(int);

void main(){
    printf("main running...\n");
    // 响应/处理 SIGALRM 闹钟信号
    signal(SIGALRM, handleSig);
    // 闹钟倒计时 5 秒
    alarm(5);
	// 暂停执行,等待被 SIGALRM 闹钟信号唤醒
    pause();
    printf("done.\n");
}

void handleSig(int sig){
    printf("wake up.\n");
}

执行结果如下(达到预期目的):

ubuntu@cuname:~/dev/beginning-linux-programming/test$ gcc -o test2 test2.c
ubuntu@cuname:~/dev/beginning-linux-programming/test$ ./test2
main running...
wake up. 	// 被 SIGALRM 闹钟信号唤醒
done.

4. 处理信号(使用 sigaction 函数)
  • signal 函数在传统的 UNIX 编程中很常见。但是 X/Open 和 UNIX 规范推荐了一个更新和更健壮的信号编程接口:sigaction
  1. sigaction 函数
#include <signal.h>
int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);

sigaction 结构定义在文件 signal.h 中,它的作用是定义在接收到参数 sig 指定的信号后应该采取的行动。该结构至少应该包括以下几个成员:
void (*) (int) sa_handler
sigset_t sa_mask
int sa_flags


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值