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

如何用fork创建可多次触发执行的等待子进程?

不用线程也能实现:fork子进程重复触发执行任务的方案

完全可以做到不用线程,通过fork创建的子进程保持存活,按需多次触发执行任务。你之前的问题是直接让子进程execve了myecho——execve会把整个子进程的程序空间替换掉,执行完就退出了,自然没法重复触发。下面给你两种靠谱的实现方式:

方式1:信号触发(最简单,适合无参数触发)

让子进程阻塞等待一个自定义信号(比如SIGUSR1),主进程每次要触发任务时就给子进程发这个信号,子进程收到后执行任务,完了继续回去等下一次信号。

示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>

// 子进程要执行的任务逻辑
void run_task() {
    printf("子进程执行任务 | PID: %d\n", getpid());
    // 用fork+execve调用myecho,确保myecho执行完后子进程仍能保持存活
    pid_t grandkid = fork();
    if (grandkid == 0) {
        execl("./myecho", "myecho", "任务触发", NULL);
        perror("调用myecho失败");
        exit(1);
    }
    waitpid(grandkid, NULL, 0); // 等待myecho执行完成
}

// 信号处理函数:收到SIGUSR1就执行任务
void handle_signal(int sig) {
    if (sig == SIGUSR1) {
        run_task();
    }
}

int main() {
    pid_t child_pid = fork();
    if (child_pid == -1) {
        perror("fork子进程失败");
        exit(1);
    }

    if (child_pid == 0) {
        // 子进程:注册信号处理,进入无限等待状态
        signal(SIGUSR1, handle_signal);
        while (1) {
            pause(); // 阻塞等待信号,不占用CPU资源
        }
        exit(0);
    } else {
        // 主进程:按需发送信号触发任务
        char input;
        printf("输入任意字符触发任务,输入q退出\n");
        while (1) {
            scanf(" %c", &input);
            if (input == 'q') {
                kill(child_pid, SIGTERM); // 终止子进程
                waitpid(child_pid, NULL, 0);
                break;
            }
            kill(child_pid, SIGUSR1); // 发送触发信号
        }
    }
    return 0;
}

方式2:管道触发(支持传参数,更灵活)

主进程和子进程建立管道,子进程阻塞读取管道内容,主进程每次要触发就往管道里写数据(可传递任务参数),子进程读到数据后执行任务,完成后继续等待下一次触发。

示例代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>

int main() {
    int pipefd[2];
    if (pipe(pipefd) == -1) {
        perror("创建管道失败");
        exit(1);
    }

    pid_t child_pid = fork();
    if (child_pid == -1) {
        perror("fork子进程失败");
        exit(1);
    }

    if (child_pid == 0) {
        // 子进程:关闭写端,读取管道等待指令
        close(pipefd[1]);
        char buf[256];
        ssize_t read_len;
        while ((read_len = read(pipefd[0], buf, sizeof(buf)-1)) > 0) {
            buf[read_len] = '\0';
            printf("子进程收到指令:%s,执行任务 | PID: %d\n", buf, getpid());
            // 用fork+execve调用myecho,支持传递参数
            pid_t grandkid = fork();
            if (grandkid == 0) {
                execl("./myecho", "myecho", buf, NULL);
                perror("调用myecho失败");
                exit(1);
            }
            waitpid(grandkid, NULL, 0);
        }
        close(pipefd[0]);
        exit(0);
    } else {
        // 主进程:关闭读端,写入指令触发任务
        close(pipefd[0]);
        char cmd[256];
        printf("输入触发指令(输入q退出):\n");
        while (1) {
            fgets(cmd, sizeof(cmd), stdin);
            cmd[strcspn(cmd, "\n")] = '\0'; // 去掉换行符
            if (strcmp(cmd, "q") == 0) {
                close(pipefd[1]); // 关闭管道让子进程读到EOF退出
                waitpid(child_pid, NULL, 0);
                break;
            }
            write(pipefd[1], cmd, strlen(cmd));
        }
    }
    return 0;
}

关键提醒

  • 不要直接让子进程execve外部程序(比如myecho),否则子进程会被完全替换成该程序,执行完就直接退出,无法重复触发。要让子进程保持存活,需让它自身进入等待循环,每次触发时要么直接执行内嵌的代码逻辑,要么fork一个孙子进程去调用execve。
  • 信号和管道的选择:信号适合简单的无参数触发,管道支持传递任务参数,灵活性更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 17:19:04