嵌入式Linux:发送实时信号

2026-10-043

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

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

  • 信号范围扩大:标准信号通常使用 SIGUSR1 和 SIGUSR2,实时信号的编号范围更大(SIGRTMIN 到 SIGRTMAX,对应编号 34~64),可用于更多自定义目的。
  • 队列化管理:同一个实时信号多次发生时,内核会记录每次事件并按顺序传递;标准信号通常只传递一次。
  • 附带数据:实时信号可以携带整型数据或指针,接收方可以在处理函数中读取。
  • 传递顺序保证:多个不同的实时信号处于等待状态时,编号越小的信号优先传递;同一个信号的多次传递保持发送顺序。

要使用实时信号,发送进程可以通过 sigqueue() 发送信号及附带数据,接收进程则需要通过 sigaction() 注册处理函数并启用 SA_SIGINFO。

sigqueue() 函数原型

sigqueue() 的函数原型如下:

#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);

参数说明:

  • pid:接收信号的进程 ID。
  • sig:要发送的信号编号,也可以设置为 0 来检查进程是否存在。
  • value:union sigval 类型的值,可以携带整型数据或指针。

成功时返回 0;失败时返回 -1,并设置 errno。

union sigval 定义如下:

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

1、发送进程

发送进程使用 sigqueue() 向另一个进程发送实时信号及其伴随数据。下面的示例从命令行读取目标进程 ID 和信号编号,并附带一个整型值:

#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", 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() 绑定实时信号处理函数,并从 siginfo_t 中读取附带数据:

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>

static void sig_handler(int sig, siginfo_t *info, void *context) {
    (void)context;
    sigval_t sig_val = info->si_value;

    printf("Received real-time signal: %d", sig);
    printf("Attached data: %d", 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;
    sigemptyset(&sa.sa_mask);

    if (sigaction(sig, &sa, NULL) == -1) {
        perror("sigaction error");
        exit(-1);
    }

    // 等待信号
    while (1) {
        sleep(1);
    }

    return 0;
}

标准信号适用于多数常见场景,但无法记录同一信号的多次发生,也不能携带附加数据。实时信号通过队列化传递和 sigqueue() 的附加值机制,适合进程间需要可靠传递事件及少量数据的场景。

来源:嵌入式Linux:发送实时信号(CSDN,原作者“不脱发的程序猿”,CC BY-SA 4.0)

创作许可协议

本项目采用 CC BY(署名) 进行许可。

评论(0)
- 没有更多了 -