嵌入式Linux:发送实时信号
非实时信号有一个明显的局限性:当同一个信号多次发生时,它只会被记录为一次,且不会记录发生的次数。因此,当该信号被解除阻塞后,它仅会被处理一次。这种行为使得标准信号在某些应用场景下不够灵活。 相比之下,实时信号 提供了几个关键的优势: - 信号范围扩大:标准信号仅提供 SIGUSR1 和 SIGUSR2 供用户自定义使用,而实时信号的编号范围更大(SIGRTMIN 到 SIGRTMAX,对应编号范围 34~64),可以应用于更多自定义目的。 - 队列化管理:实时信号采取队列化管理,这意味着如果同一个实时信号多次发生,内核将记录每次事件并按顺序传递,而标准信号只会传递一次。 - 附带数据:实时信号允许携带附带数据(可以是整型数据或指针),供接收方在信号处理函数中使用,这为信号传递带来了更大的灵活性。 - 传递顺序保证:当多个不同的实时信号处于等待状态时,信号编号越小的信号会优先传递。如果同一个信号多次发生,传递顺序会与发送顺序保持一致。 为了使用实时信号,通常需要满足以下要求: - 发送实时信号:发送进程需要使用 sigqueue() 系统调用发送实时信号及其伴随数据。 - 接收实时信号:接收进程需要为该信号设置信号处理函数,并在 sigaction 函数中启用 SA_SIGINFO 标志,以确保可以接收伴随数据。 sigqueue() 的函数原型如下: ```c #include 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 是一个共用体,定义如下: ```c typedef union sigval { int sival_int; // 整型数据 void *sival_ptr; // 指针数据 } sigval_t; ``` ## 1、发送进程 使用 sigqueue() 向另一个进程发送实时信号及其伴随数据。 ```c #include #include #include int main(int argc, char *argv[]) { union sigval sig_val; int pid, sig; // 检查参数个数 if (argc #include #include #include 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 信号处理机制中各有优劣。标准信号适用于大多数常见场景,但其无法记录信号的多次发生,且缺少附带数据传递的能力。而实时信号则提供了更灵活的功能,包括多次传递信号、附带数据和保证传递顺序。这些特性使得实时信号在高性能和复杂信号处理需求下尤为有用。 作者:不脱发的程序猿。本文转载自作者CSDN博客。原文:https://handsome-man.blog.csdn.net/article/details/141756910