You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言自定义信号触发与处理异常:signal函数调用失败排查

问题:C语言自定义信号处理失败的原因分析

我正在尝试在C语言中触发并处理自定义信号,但仅取得部分成功。已知SIGINT这类标准信号能正常触发sigHandler,但自定义信号相关的signal调用返回负值,说明signal函数的使用存在问题。我的最终目标是针对不同信号执行对应操作,目前仅希望能进入switch分支并输出对应信息。

我的代码如下:

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

sig_atomic_t signaled = 0;

#define TEST_SIGNAL_50 50
#define TEST_SIGNAL_51 51
#define TEST_SIGNAL_52 52
#define SIGUSR1 50

void sigHandler(int sig)
{
    signaled = 1;

    //Switch statement to handle all signals
    switch(sig) {
        case TEST_SIGNAL_50:
            printf("Case 50 is Matched.\n");
            break;
        case TEST_SIGNAL_51:
            printf("Case 51 is Matched.\n");
            break;
        case TEST_SIGNAL_52:
            printf("Case 52 is Matched.\n");
            break;
        case SIGINT:
            printf("SIGINT Case is Matched.\n");
            break;
        default:    //Raised signal is not a match
            printf("Raised signal %d is not a match.\n", sig);
            break;

    }
}

int main() {
    printf("Hello, World! Test\n");
    
    int raiseResult;
    void (*prev_handler)(int);

    //Register the signal handler
    //prev_handler = signal(SIGINT, sigHandler);     //This works
    //prev_handler = signal(TEST_SIGNAL_50, sigHandler);
    prev_handler = signal(SIGUSR1, sigHandler);

    /* ... */
    //raiseResult = raise(SIGINT);                  //This works
    raiseResult = raise(SIGUSR1);
    /* ... */

    printf("raiseResult =%d.\n",raiseResult );
  
    printf("signaled =%d.\n",signaled);
  
    return 0;
}

解决方法

你的问题出在对信号编号的错误使用上,具体问题和修复方式如下:

  1. 错误覆盖系统预定义信号
    你手动#define SIGUSR1 50是完全错误的:系统头文件已经预定义了SIGUSR1和SIGUSR2这两个专门给用户使用的标准信号,它们的编号在不同系统上可能不同(比如Linux下SIGUSR1是10,SIGUSR2是12)。你强行重定义会覆盖系统的正确值,导致signal函数收到无效的信号编号,返回SIG_ERR(即你看到的负值)。

  2. 自定义信号编号不能随意指定
    你定义的TEST_SIGNAL_50这类固定编号不可靠:不同系统的信号编号范围是固定的,普通信号(非实时)的编号通常在1-31之间,实时信号从SIGRTMIN到SIGRTMAX(Linux下通常是34-64)。直接用50作为信号编号,要么超出系统允许的范围,要么该编号已经被系统占用,导致signal调用失败。

  3. 正确的实现方式

    • 删除自己定义的#define SIGUSR1 50,直接使用系统提供的SIGUSR1/SIGUSR2。
    • 如果需要更多自定义信号,使用实时信号:基于SIGRTMIN来定义,比如#define TEST_SIGNAL_1 (SIGRTMIN + 0),这样能保证编号在系统允许的范围内。
    • 注意:printf不是异步信号安全函数,在信号处理函数中使用可能导致未定义行为,实际开发建议用write函数输出到stderr。

修改后的示例代码:

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

sig_atomic_t signaled = 0;

// 使用系统预定义用户信号,或基于SIGRTMIN定义实时信号
#define TEST_SIGNAL_1 (SIGRTMIN + 0)
#define TEST_SIGNAL_2 (SIGRTMIN + 1)

void sigHandler(int sig)
{
    signaled = 1;
    char msg[100];
    int len;

    switch(sig) {
        case TEST_SIGNAL_1:
            len = snprintf(msg, sizeof(msg), "Case TEST_SIGNAL_1 is Matched.\n");
            write(STDERR_FILENO, msg, len);
            break;
        case TEST_SIGNAL_2:
            len = snprintf(msg, sizeof(msg), "Case TEST_SIGNAL_2 is Matched.\n");
            write(STDERR_FILENO, msg, len);
            break;
        case SIGUSR1:
            len = snprintf(msg, sizeof(msg), "SIGUSR1 Case is Matched.\n");
            write(STDERR_FILENO, msg, len);
            break;
        case SIGINT:
            len = snprintf(msg, sizeof(msg), "SIGINT Case is Matched.\n");
            write(STDERR_FILENO, msg, len);
            break;
        default:
            len = snprintf(msg, sizeof(msg), "Raised signal %d is not a match.\n", sig);
            write(STDERR_FILENO, msg, len);
            break;
    }
}

int main() {
    printf("Hello, World! Test\n");
    
    int raiseResult;
    void (*prev_handler)(int);

    // 注册SIGUSR1处理器,增加错误判断
    prev_handler = signal(SIGUSR1, sigHandler);
    if (prev_handler == SIG_ERR) {
        perror("Failed to set SIGUSR1 handler");
        exit(EXIT_FAILURE);
    }

    // 注册自定义实时信号处理器
    prev_handler = signal(TEST_SIGNAL_1, sigHandler);
    if (prev_handler == SIG_ERR) {
        perror("Failed to set TEST_SIGNAL_1 handler");
        exit(EXIT_FAILURE);
    }

    // 触发SIGUSR1
    raiseResult = raise(SIGUSR1);
    if (raiseResult != 0) {
        perror("Failed to raise SIGUSR1");
    }

    // 触发自定义实时信号
    raiseResult = raise(TEST_SIGNAL_1);
    if (raiseResult != 0) {
        perror("Failed to raise TEST_SIGNAL_1");
    }

    printf("raiseResult =%d.\n",raiseResult );
    printf("signaled =%d.\n",signaled);
  
    return 0;
}

内容的提问来源于stack exchange,提问作者lordmichael95

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 11:38:10