新闻  |   论坛  |   博客  |   在线研讨会
嵌入式Linux:发送实时信号
美男子玩编程 | 2024-10-12 09:40:34    阅读:35   发布文章

非实时信号有一个明显的局限性:当同一个信号多次发生时,它只会被记录为一次,且不会记录发生的次数。因此,当该信号被解除阻塞后,它仅会被处理一次。这种行为使得标准信号在某些应用场景下不够灵活。

相比之下,实时信号 提供了几个关键的优势:

  • 信号范围扩大:标准信号仅提供 SIGUSR1 和 SIGUSR2 供用户自定义使用,而实时信号的编号范围更大(SIGRTMIN 到 SIGRTMAX,对应编号范围 34~64),可以应用于更多自定义目的。

  • 队列化管理:实时信号采取队列化管理,这意味着如果同一个实时信号多次发生,内核将记录每次事件并按顺序传递,而标准信号只会传递一次。

  • 附带数据:实时信号允许携带附带数据(可以是整型数据或指针),供接收方在信号处理函数中使用,这为信号传递带来了更大的灵活性。

  • 传递顺序保证:当多个不同的实时信号处于等待状态时,信号编号越小的信号会优先传递。如果同一个信号多次发生,传递顺序会与发送顺序保持一致。


为了使用实时信号,通常需要满足以下要求:

  • 发送实时信号:发送进程需要使用 sigqueue() 系统调用发送实时信号及其伴随数据。

  • 接收实时信号:接收进程需要为该信号设置信号处理函数,并在 sigaction 函数中启用 SA_SIGINFO 标志,以确保可以接收伴随数据。


sigqueue() 的函数原型如下:


#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 是一个共用体,定义如下:


typedef union sigval {    int sival_int;    // 整型数据    void *sival_ptr;  // 指针数据} sigval_t;

1


发送进程

使用 sigqueue() 向另一个进程发送实时信号及其伴随数据。

#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() 绑定实时信号处理函数,并接收伴随数据。


#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 信号处理机制中各有优劣。标准信号适用于大多数常见场景,但其无法记录信号的多次发生,且缺少附带数据传递的能力。而实时信号则提供了更灵活的功能,包括多次传递信号、附带数据和保证传递顺序。这些特性使得实时信号在高性能和复杂信号处理需求下尤为有用。

*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。

参与讨论
登录后参与讨论
推荐文章
最近访客