嵌入式Linux:发送实时信号

目录

1、发送进程

2、接收进程


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

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

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