问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

进程间通信信号(Signals)详解

创作时间:
作者:
@小白创作中心

进程间通信信号(Signals)详解

引用
1
来源
1.
https://2743.com/archives/17449

在Linux和Unix系统中,信号(Signal)是一种进程间通信(IPC)机制,用于通知进程发生了某种事件。信号是一种异步的通知方式,操作系统或其他进程可以随时向目标进程发送信号,以让其执行特定的操作,如终止、暂停、继续运行等。

一、什么是信号(Signals)?

  • 信号是进程间的异步通知机制,可以用于通知进程某个事件发生,如中断、终止、挂起等。
  • 进程可以接收、忽略、处理信号(但某些信号无法被捕获或忽略,如SIGKILL)。
  • 信号是由内核、用户、硬件触发的。
  • 进程可以使用kill命令或kill()系统调用向其他进程发送信号。

二、常见的 Linux 信号列表

信号编号
信号名称
默认动作
说明
1
SIGHUP
终止
终端关闭、会话结束时发送
2
SIGINT
终止
用户按Ctrl+C终止进程
3
SIGQUIT
终止 + Dump
Ctrl+\退出进程,生成 core dump
9
SIGKILL
终止
强制终止进程,不可捕获/忽略
11
SIGSEGV
终止 + Dump
段错误(Segmentation Fault)
15
SIGTERM
终止
默认的进程终止信号,可被捕获和忽略
18
SIGCONT
继续
让一个停止的进程继续运行
19
SIGSTOP
停止
强制暂停进程,不可捕获/忽略
20
SIGTSTP
停止
Ctrl+Z发送,让进程进入后台
  • SIGKILLSIGSTOP无法被进程捕获或忽略,确保系统可以终止或挂起进程。
  • SIGTERM是最常用的终止进程信号,可由进程处理或忽略。

在终端运行kill -l命令, 可查看Linux支持的信号列表:

其中,编号为1 ~ 31的信号为传统UNIX支持的信号,是不可靠信号(非实时的);编号为34 ~ 63的信号是后来扩充的,为可靠信号(实时信号)。

不可靠信号和可靠信号的区别在于前者不支持排队,可能会造成信号丢失,而后者不会。

三、发送信号

3.1 kill命令

kill用于向进程发送信号:

kill -SIGNAL PID
kill -9 1234 # 发送 SIGKILL 终止进程 1234
kill -15 5678 # 发送 SIGTERM(默认)终止进程 5678

如果不指定信号,默认发送SIGTERM

kill 5678 # 等价于 kill -15 5678

3.2 pkillkillall

pkill通过进程名发送信号:

pkill -9 firefox # 强制终止所有名为 firefox 的进程

killall终止所有匹配名称的进程:

killall -15 python # 发送 SIGTERM 终止所有 Python 进程

3.3 kill()系统调用

在C语言中,可以使用kill()发送信号:

#include <signal.h>
#include <unistd.h>
#include <stdio.h>
int main() {
    pid_t pid = 1234; // 替换为目标进程 PID
    kill(pid, SIGKILL); // 向进程发送 SIGKILL
    return 0;
}

3.4 raise()向自己发送信号

#include <signal.h>
#include <stdio.h>
int main() {
    printf("Sending SIGTERM to self...\n");
    raise(SIGTERM); // 进程向自己发送 SIGTERM
    return 0;
}

3.5 sigqueue()发送带数据的信号

#include <signal.h>
#include <stdio.h>
int main() {
    pid_t pid = 1234; // 目标进程 PID
    union sigval value;
    value.sival_int = 42; // 传递的数据
    sigqueue(pid, SIGTERM, value);
    return 0;
}

四、处理信号

进程可以使用signal()sigaction()处理信号。

4.1 signal()处理信号

#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void handler(int signum) {
    printf("Received signal %d\n", signum);
}
int main() {
    signal(SIGINT, handler); // 捕获 SIGINT (Ctrl+C)
    while (1) {
        sleep(1);
    }
    return 0;
}

运行后,按Ctrl+C发送SIGINT,进程不会终止,而是打印Received signal 2

4.2 sigaction()处理信号

sigaction()提供更强的信号控制功能:

#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void handler(int signum) {
    printf("Caught signal %d\n", signum);
}
int main() {
    struct sigaction sa;
    sa.sa_handler = handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGINT, &sa, NULL);
    while (1) {
        sleep(1);
    }
    return 0;
}

sigaction()可以替代signal(),支持更高级的信号处理。

五、屏蔽信号

sigprocmask()屏蔽信号

可以使用sigprocmask()屏蔽信号,使进程暂时忽略某些信号:

#include <signal.h>
#include <stdio.h>
#include <unistd.h>
int main() {
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGINT); // 屏蔽 SIGINT
    sigprocmask(SIG_BLOCK, &set, NULL);
    printf("SIGINT is blocked. Press Ctrl+C, but nothing happens.\n");
    sleep(10);
    sigprocmask(SIG_UNBLOCK, &set, NULL);
    printf("SIGINT is now unblocked.\n");
    while (1) sleep(1);
    return 0;
}

SIG_BLOCK屏蔽信号,SIG_UNBLOCK解除屏蔽。

六、挂起进程等待信号

6.1 pause()等待信号

#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void handler(int signum) {
    printf("Caught signal %d, exiting...\n", signum);
}
int main() {
    signal(SIGINT, handler);
    printf("Waiting for signal...\n");
    pause(); // 挂起进程,直到接收到信号
    return 0;
}

6.2 sigwait()主动等待信号

#include <signal.h>
#include <stdio.h>
int main() {
    sigset_t set;
    int signum;
    sigemptyset(&set);
    sigaddset(&set, SIGINT);
    sigprocmask(SIG_BLOCK, &set, NULL);
    printf("Waiting for SIGINT...\n");
    sigwait(&set, &signum);
    printf("Received signal %d\n", signum);
    return 0;
}

七、总结

  • 信号是进程间通信的重要方式,用于通知进程发生事件,如终止、暂停、继续等。
  • 进程可以使用killraisesigqueue发送信号。
  • 进程可以使用signal()sigaction()处理信号。
  • 可以使用sigprocmask()屏蔽信号,pause()sigwait()挂起进程等待信号。

掌握信号机制对编写可靠的后台服务、守护进程、异常处理等至关重要!

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号