pthread_kill()发送SIGALRM导致程序终止问题求助
问题分析与解决方案
问题根源
核心问题是线程创建后,主线程发送SIGALRM的时机早于子线程完成信号处理函数的注册。SIGALRM的默认处理动作是终止整个进程,当子线程还没来得及调用sigaction设置自定义处理函数时,信号会触发默认行为,直接终止程序。而添加sleep(1)只是靠延迟给了子线程完成注册的时间,这种依赖时间的同步方式完全不可靠——不同环境下线程启动、执行的速度不同,很容易在其他场景下复现问题。
可靠的解决方案:用线程同步机制替代sleep
方案1:使用条件变量+互斥锁
通过同步机制让主线程等待,直到子线程明确告知已完成信号处理函数的注册:
#include <pthread.h> #include <signal.h> #include <stdio.h> #include <unistd.h> pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; int handler_registered = 0; void obsluga(int sig) { printf("子线程捕获到SIGALRM信号\n"); } void* funkcja_watku(){ struct sigaction new_action = {.sa_handler = obsluga}; // 注册信号处理函数 if (sigaction(SIGALRM, &new_action, NULL) == -1) { perror("sigaction失败"); pthread_exit(NULL); } // 通知主线程:已完成注册 pthread_mutex_lock(&mutex); handler_registered = 1; pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); // 等待信号,无需sleep pause(); // 暂停线程直到收到信号 return NULL; } int main(int argc, const char * argv[]) { pthread_t watek_id; if(pthread_create(&watek_id, NULL, &funkcja_watku, NULL)) { perror("Watek nie zostal utworzony"); return 1; } // 等待子线程完成信号处理函数注册 pthread_mutex_lock(&mutex); while (!handler_registered) { pthread_cond_wait(&cond, &mutex); } pthread_mutex_unlock(&mutex); // 此时发送信号,子线程已准备好 if(pthread_kill(watek_id, SIGALRM)) { perror("Sygnal nie zostal wyslany"); return 1; } if(pthread_join(watek_id, NULL)) { perror("Watek nie zostal usuniety"); return 1; } return 0; }
方案2:使用线程屏障(pthread_barrier)
如果只需要简单的同步点,线程屏障更简洁:
#include <pthread.h> #include <signal.h> #include <stdio.h> #include <unistd.h> pthread_barrier_t barrier; void obsluga(int sig) { printf("子线程捕获到SIGALRM信号\n"); } void* funkcja_watku(){ struct sigaction new_action = {.sa_handler = obsluga}; if (sigaction(SIGALRM, &new_action, NULL) == -1) { perror("sigaction失败"); pthread_exit(NULL); } // 等待主线程到达同步点 pthread_barrier_wait(&barrier); pause(); return NULL; } int main(int argc, const char * argv[]) { // 初始化屏障,等待2个线程(主线程+子线程) pthread_barrier_init(&barrier, NULL, 2); pthread_t watek_id; if(pthread_create(&watek_id, NULL, &funkcja_watku, NULL)) { perror("Watek nie zostal utworzony"); return 1; } // 等待子线程完成注册 pthread_barrier_wait(&barrier); if(pthread_kill(watek_id, SIGALRM)) { perror("Sygnal nie zostal wyslany"); return 1; } if(pthread_join(watek_id, NULL)) { perror("Watek nie zostal usuniety"); return 1; } pthread_barrier_destroy(&barrier); return 0; }
额外注意事项
- 信号处理函数
obsluga要符合信号安全要求:不能调用非线程安全、非信号安全的函数(比如printf其实不是严格信号安全的,实际生产环境建议用write替代)。 - 子线程里的
sleep(2)可以替换为pause(),更高效——pause()会一直阻塞直到收到信号,避免不必要的延迟。
内容的提问来源于stack exchange,提问作者Єгорій
相关产品推荐
相关产品推荐

