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

如何无需等待固定时长,直接等待进程完成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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 14:45:24