目录
非实时信号有一个明显的局限性:当同一个信号多次发生时,它只会被记录为一次,且不会记录发生的次数。因此,当该信号被解除阻塞后,它仅会被处理一次。这种行为使得标准信号在某些应用场景下不够灵活。
相比之下,实时信号 提供了几个关键的优势:
-
信号范围扩大 :标准信号仅提供
SIGUSR1
和SIGUSR2
供用户自定义使用,而实时信号的编号范围更大(SIGRTMIN
到SIGRTMAX
,对应编号范围 34~64),可以应用于更多自定义目的。 -
队列化管理:实时信号采取队列化管理,这意味着如果同一个实时信号多次发生,内核将记录每次事件并按顺序传递,而标准信号只会传递一次。
-
附带数据:实时信号允许携带附带数据(可以是整型数据或指针),供接收方在信号处理函数中使用,这为信号传递带来了更大的灵活性。
-
传递顺序保证:当多个不同的实时信号处于等待状态时,信号编号越小的信号会优先传递。如果同一个信号多次发生,传递顺序会与发送顺序保持一致。
为了使用实时信号,通常需要满足以下要求:
- 发送实时信号 :发送进程需要使用
sigqueue()
系统调用发送实时信号及其伴随数据。 - 接收实时信号 :接收进程需要为该信号设置信号处理函数,并在
sigaction
函数中启用SA_SIGINFO
标志,以确保可以接收伴随数据。
sigqueue()
的函数原型如下:
cpp
#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);
-
参数:
pid
:接收信号的进程 ID。sig
:需要发送的信号编号。与kill()
类似,也可以将sig
设置为 0 来检查进程是否存在。value
:一个union sigval
类型的值,表示伴随信号传递的数据,可以是整型或指针。
-
返回值:
- 成功返回 0;
- 失败返回 -1,并设置
errno
。
union sigval
是一个共用体,定义如下:
cpp
typedef union sigval {
int sival_int; // 整型数据
void *sival_ptr; // 指针数据
} sigval_t;
1、发送进程
使用 sigqueue()
向另一个进程发送实时信号及其伴随数据。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int main(int argc, char *argv[]) {
union sigval sig_val;
int pid, sig;
// 检查参数个数
if (argc < 3) {
exit(-1);
}
// 获取命令行传递的参数
pid = atoi(argv[1]);
sig = atoi(argv[2]);
printf("Sending signal %d to process %d\n", sig, pid);
// 发送信号,附带整型数据
sig_val.sival_int = 10;
if (sigqueue(pid, sig, sig_val) == -1) {
perror("sigqueue error");
exit(-1);
}
puts("Signal sent successfully!");
return 0;
}
2、接收进程
使用 sigaction()
绑定实时信号处理函数,并接收伴随数据。
cpp
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
static void sig_handler(int sig, siginfo_t *info, void *context) {
sigval_t sig_val = info->si_value;
printf("Received real-time signal: %d\n", sig);
printf("Attached data: %d\n", sig_val.sival_int);
}
int main(int argc, char *argv[]) {
struct sigaction sa = {0};
int sig;
// 检查参数个数
if (argc < 2) {
exit(-1);
}
// 获取命令行传递的信号编号
sig = atoi(argv[1]);
// 绑定信号处理函数
sa.sa_sigaction = sig_handler;
sa.sa_flags = SA_SIGINFO; // 启用 SA_SIGINFO 标志,以接收附带数据
if (sigaction(sig, &sa, NULL) == -1) {
perror("sigaction error");
exit(-1);
}
// 无限循环,等待信号
while (1) {
sleep(1);
}
return 0;
}
标准信号和实时信号在 Linux 信号处理机制中各有优劣。标准信号适用于大多数常见场景,但其无法记录信号的多次发生,且缺少附带数据传递的能力。而实时信号则提供了更灵活的功能,包括多次传递信号、附带数据和保证传递顺序。这些特性使得实时信号在高性能和复杂信号处理需求下尤为有用。