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

C语言中fork()、信号与父子进程的技术疑问

我来帮你拆解清楚这些疑惑,一步步捋明白:

一、父子进程的核心定义

当一个进程调用fork()系统调用时,操作系统会生成一个全新的进程——这个新进程就是子进程,而发起fork()的那个原始进程就是父进程。

  • 子进程是父进程的「几乎完美副本」:它会复制父进程的代码、内存里的变量、打开的文件、信号处理规则等所有状态,但两者拥有完全独立的内存空间——子进程里的变量修改不会影响父进程,反之亦然。
  • 父子进程是并行执行的,操作系统的调度器会决定哪个进程先拿到CPU时间片,所以它们的执行顺序默认是不确定的(除非用wait()这类同步函数干预)。

二、signal(SIGUSR1, Paris);到底做了什么

signal()是用来给进程「注册信号处理规则」的函数:

  • 第一个参数SIGUSR1是一个用户自定义信号——这类信号是专门留给程序员在程序内部传递自定义事件的,系统不会主动发送它,得我们手动触发。
  • 第二个参数Paris是一个函数指针,意思是:当当前进程收到SIGUSR1信号时,就暂停当前正在跑的代码,转而去执行Paris函数,执行完再回到之前的代码继续跑。

三、kill(getpid(), SIGUSR1);的作用是什么

kill()函数的本职工作是给指定进程发送信号,参数含义是:

  • 第一个参数是目标进程的PID(进程ID),getpid()会返回当前进程自己的PID。
  • 第二个参数是要发送的信号,这里是SIGUSR1。
    所以整句话的意思就是:给当前进程自己发送SIGUSR1信号,这样就会触发之前用signal()注册好的Paris函数执行,输出Paris。

四、关于输出顺序的疑问

你预期输出London StayHome Paris,这个结果是有可能出现的,但不是绝对的——因为父子进程并行执行,调度器可能先让子进程跑(输出StayHome),也可能先让父进程触发信号输出Paris。
如果想强制这个顺序,让父进程先等子进程跑完再执行信号逻辑,可以在父进程的kill()之前加一句wait(NULL),这样父进程会暂停,直到子进程退出,就能保证StayHome一定在Paris前面输出。

举个补全后的完整代码示例,方便你理解:

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

void Paris() {
    printf("Paris ");
}

void StayHome() {
    printf("StayHome ");
}

int main() {
    printf("London ");
    // 注册SIGUSR1的处理函数
    signal(SIGUSR1, Paris);
    // 创建子进程
    pid_t pid = fork();

    if (pid == 0) {
        // 子进程分支:输出StayHome后退出
        StayHome();
        return 0;
    } else if (pid > 0) {
        // 父进程分支:先等子进程跑完,再给自己发信号
        wait(NULL);
        kill(getpid(), SIGUSR1);
        return 0;
    } else {
        // fork失败的情况
        perror("fork failed");
        return 1;
    }
}

这段代码运行后会稳定输出London StayHome Paris。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:49:25