写一个linux下不断产生信号的demo

以下是一个在Linux下周期性地产生信号的示例程序。该程序每秒触发一次SIGALRM信号,并在信号处理函数中重置定时器以实现持续触发:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>

void handler(int signum) {
char msg[] = "Signal received\n";
write(STDOUT_FILENO, msg, sizeof(msg) - 1); // 安全地输出信息
alarm(1); // 重新设置定时器以实现循环触发
}

int main() {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler; // 设置信号处理函数
sigemptyset(&sa.sa_mask); // 不阻塞其他信号

if (sigaction(SIGALRM, &sa, NULL) == -1) {
perror("sigaction");
return 1;
}

alarm(1); // 首次触发定时器(1秒后发送SIGALRM)

while (1) {
pause(); // 暂停进程,等待信号
}

return 0;
}

说明:

  1. 信号选择:使用SIGALRM定时器信号,通过alarm函数设置定时触发。
  2. 信号处理
    • handler函数中调用alarm(1)实现定时器循环。
    • 使用write而非printf,避免信号处理中调用不可重入函数。
  3. 安全性
    • 使用sigaction注册信号处理函数(比signal更可靠)。
    • 通过sigemptyset清空阻塞信号集,确保处理函数执行时不阻塞其他信号。

编译运行:

  1. 保存为signal_demo.c
  2. 终端执行:
    1
    2
    gcc signal_demo.c -o signal_demo
    ./signal_demo
  3. 程序每秒输出一次Signal received,按Ctrl+C终止。

扩展:

  • 修改alarm(1)中的数值调整触发间隔(单位:秒)。
  • 替换SIGALRM为其他信号(如SIGUSR1),需配合kill(getpid(), SIGUSR1)在处理函数中手动触发。

Linux下发送信号

在 Linux 系统中,发送信号是进程间通信(IPC)的重要方式。以下是发送信号的常见方法(命令行工具 + 编程实现),以及对应的原理和示例:


一、命令行发送信号

1. kill 命令

语法

1
2
kill -<SIGNAL> <PID>          # 向指定进程发送信号
kill -<SIGNAL> -<PGID> # 向进程组发送信号

示例

1
2
3
kill -SIGTERM 1234           # 向 PID=1234 的进程发送终止信号(默认信号为 SIGTERM)
kill -9 5678 # 强制杀死 PID=5678 的进程(SIGKILL)
kill -SIGHUP $(pgrep nginx) # 向所有 nginx 进程发送重新加载配置信号

2. pkill / killall 命令

1
2
pkill -<SIGNAL> <进程名>      # 按进程名发送信号(支持正则)
killall -<SIGNAL> <进程名> # 按精确进程名发送信号

示例

1
2
pkill -SIGUSR1 chrome       # 向所有 chrome 进程发送自定义信号
killall -SIGTERM firefox # 终止所有 firefox 进程

二、编程发送信号(C语言)

1. kill() 函数

原型

1
2
#include <signal.h>
int kill(pid_t pid, int sig); // 向指定进程/进程组发送信号

参数

  • pid > 0:目标进程的 PID
  • pid == 0:发送给当前进程组的所有进程
  • pid == -1:广播信号(需要权限)
  • pid < -1:发送给进程组 ID 为 |pid| 的进程组

示例

1
2
3
4
5
6
7
8
9
10
#include <signal.h>
#include <unistd.h>

int main() {
pid_t target_pid = 1234;
if (kill(target_pid, SIGTERM) == -1) {
perror("kill failed");
}
return 0;
}

2. raise() 函数

当前进程自身发送信号:

1
2
#include <signal.h>
int raise(int sig); // 等效于 kill(getpid(), sig)

三、其他工具发送信号

1. Python 脚本

1
2
3
4
import os
import signal

os.kill(pid, signal.SIGTERM) # 向指定 PID 发送信号

2. 键盘组合键

  • Ctrl + C → 发送 SIGINT(终止进程)
  • Ctrl + \ → 发送 SIGQUIT(终止并生成 core dump)
  • Ctrl + Z → 发送 SIGTSTP(挂起进程)

四、常见信号列表

信号名 默认行为 用途
SIGHUP 1 终止 终端挂断/重新加载配置
SIGINT 2 终止 键盘中断(Ctrl+C)
SIGQUIT 3 终止 + core dump 键盘退出(Ctrl+\)
SIGKILL 9 终止 强制杀死进程(不可捕获)
SIGTERM 15 终止 优雅终止进程(默认信号)
SIGUSR1 10 终止 用户自定义信号
SIGUSR2 12 终止 用户自定义信号

五、注意事项

  1. 权限限制

    • 普通用户只能向自己的进程发送信号。
    • SIGKILLSIGSTOP 不能被捕获、阻塞或忽略。
  2. PID 有效性

    • 确保目标 PID 存在,否则 kill() 会返回错误(ESRCH)。
  3. 竞态条件

    • 在多进程编程中,发送信号前应检查目标进程是否存活。

通过上述方法,您可以灵活控制进程行为,如优雅终止服务(SIGTERM)、强制杀死卡死进程(SIGKILL),或通过自定义信号(SIGUSR1/SIGUSR2)实现进程间协作。