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; }
解决方法
你的问题出在对信号编号的错误使用上,具体问题和修复方式如下:
错误覆盖系统预定义信号
你手动#define SIGUSR1 50是完全错误的:系统头文件已经预定义了SIGUSR1和SIGUSR2这两个专门给用户使用的标准信号,它们的编号在不同系统上可能不同(比如Linux下SIGUSR1是10,SIGUSR2是12)。你强行重定义会覆盖系统的正确值,导致signal函数收到无效的信号编号,返回SIG_ERR(即你看到的负值)。自定义信号编号不能随意指定
你定义的TEST_SIGNAL_50这类固定编号不可靠:不同系统的信号编号范围是固定的,普通信号(非实时)的编号通常在1-31之间,实时信号从SIGRTMIN到SIGRTMAX(Linux下通常是34-64)。直接用50作为信号编号,要么超出系统允许的范围,要么该编号已经被系统占用,导致signal调用失败。正确的实现方式
- 删除自己定义的
#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
相关产品推荐
相关产品推荐

