如何无需等待固定时长,直接等待进程完成SIGINT信号阻塞?
精准等待进程完成信号阻塞的几种方案
你可以用进程间同步机制替代盲等,让测试逻辑在进程完成pthread_sigmask阻塞后立刻发送SIGINT,不用靠sleep猜时间,下面是几种实用的实现方式:
1. 管道同步(跨平台首选)
这是最简单可靠的方案,利用管道的阻塞读特性实现同步:
- 目标进程在完成SIGINT阻塞后,向管道写端写入一个标记字符
- 测试脚本/父进程启动目标进程后,立刻从管道读端读取数据,读到数据就说明阻塞完成,马上发信号
目标进程代码片段(C)
#include <stdio.h> #include <pthread.h> #include <signal.h> #include <unistd.h> #include <sys/stat.h> #include <fcntl.h> int main(int argc, char* argv[]) { if (argc != 2) { fprintf(stderr, "Usage: %s <sync-pipe-path>\n", argv[0]); return 1; } // 阻塞SIGINT信号 sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGINT); if (pthread_sigmask(SIG_BLOCK, &mask, NULL) != 0) { perror("pthread_sigmask failed"); return 1; } // 打开命名管道并发送就绪信号 int pipe_fd = open(argv[1], O_WRONLY); if (pipe_fd == -1) { perror("open pipe failed"); return 1; } write(pipe_fd, "ok", 1); close(pipe_fd); // 等待并处理SIGINT int received_sig; sigwait(&mask, &received_sig); printf("Handled SIGINT\n"); return 0; }
测试脚本(bash)
#!/bin/bash # 创建命名管道 SYNC_PIPE="/tmp/sync_pipe_$$" mkfifo "$SYNC_PIPE" # 启动目标进程,传入管道路径 ./your_process "$SYNC_PIPE" & PID=$! # 阻塞等待就绪信号 read -n 1 < "$SYNC_PIPE" # 同步完成,发送SIGINT kill -SIGINT "$PID" wait "$PID" # 清理管道 rm "$SYNC_PIPE"
2. POSIX信号量同步(Linux环境适用)
用命名信号量实现跨进程同步:
- 目标进程初始化一个命名信号量,初始值为0
- 完成阻塞后调用
sem_post释放信号量 - 测试端调用
sem_wait等待,直到信号量可用再发送SIGINT
目标进程代码片段(C)
#include <stdio.h> #include <pthread.h> #include <signal.h> #include <semaphore.h> int main() { // 初始化命名信号量(初始值0) sem_t* sync_sem = sem_open("/sig_block_sync", O_CREAT | O_EXCL, 0644, 0); if (sync_sem == SEM_FAILED) { perror("sem_open failed"); return 1; } // 阻塞SIGINT信号 sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGINT); if (pthread_sigmask(SIG_BLOCK, &mask, NULL) != 0) { perror("pthread_sigmask failed"); return 1; } // 发送就绪信号 sem_post(sync_sem); // 等待并处理SIGINT int received_sig; sigwait(&mask, &received_sig); printf("Handled SIGINT\n"); sem_close(sync_sem); sem_unlink("/sig_block_sync"); return 0; }
测试辅助脚本(Python)
import os import signal import semaphore # 替换为目标进程的PID TARGET_PID = 12345 # 等待信号量就绪 sem = semaphore.Semaphore("/sig_block_sync") sem.acquire() # 发送SIGINT os.kill(TARGET_PID, signal.SIGINT)
3. 临时文件标记(简单场景凑合用)
目标进程完成阻塞后创建一个带PID的临时文件,测试脚本轮询检查文件是否存在:
- 目标进程完成阻塞后执行:
snprintf(tmp_path, sizeof(tmp_path), "/tmp/block_done_%d", getpid()); close(open(tmp_path, O_CREAT | O_RDWR, 0644)); - 测试脚本:
#!/bin/bash ./your_process & PID=$! # 轮询等待标记文件 while [ ! -f "/tmp/block_done_$PID" ]; do sleep 0.1; done # 发送SIGINT kill -SIGINT "$PID" wait "$PID" rm "/tmp/block_done_$PID"
这种方式实现最简单,但轮询会有微小延迟,适合对精度要求不高的场景。
核心逻辑
不管用哪种方式,本质都是让目标进程在执行完pthread_sigmask后,主动给测试逻辑发一个"就绪"信号,测试逻辑收到信号再触发SIGINT,彻底消除不确定的等待时间。
内容的提问来源于stack exchange,提问作者Jonathan Woollett-light
相关产品推荐
相关产品推荐

