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

为何UNIX中未调用wait()的父进程总晚于子进程执行?

为何未调用wait(),文件内容却始终为"ba"?

问题背景

作业题

Q7:执行以下代码后会生成名为myFile.txt的新文件,该文件的内容是否一致?为什么?

代码片段

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/wait.h>
int main(int argc, char *argv[]){
    printf("hello world (pid:%d)\n", (int)getpid());
    int fd = open("myFile.txt", O_CREAT|O_RDWR);
    if(fd == -1 ) {
        printf("Unable to open the file\n exiting....\n");
        return 0;
    }
    
    int rc = fork();
    
    
    if (rc < 0) {
        fprintf(stderr, "fork failed\n");
        exit(1);
    }
    else if (rc == 0) {
        printf("hello, I am child (pid:%d)\n", (int)getpid());
        char myChar='a';
        write(fd, &myChar,1);
        printf("writing a character to the file from child\n");
    }
    else {
        printf("hello, I am parent of %d (pid:%d)\n",
               rc, (int)getpid());
        char myChar='b';
        write(fd, &myChar,1);
        printf("writing a character to the file from parent\n");
    }
return 0;
}

实际观察与疑问

实际运行时,父进程写入字符'b',子进程写入字符'a'。多次执行程序后发现文件内容始终为"ba"——即父进程的写入总是先于子进程,但代码中父进程并未调用wait()函数来等待子进程,恳请解释其中原因。


核心原因分析

1. 进程调度与操作执行的异步性

fork()调用完成后,内核会自主决定先调度父进程还是子进程,这本身是不确定的,但在低负载环境中,子进程更频繁地被优先调度,导致子进程的printf输出先出现在终端。但要注意:

  • printf(终端I/O)和write(文件I/O)是两个独立的系统调用,进程间没有任何同步机制约束它们的执行顺序。
  • 子进程执行完printf后,可能因为终端I/O的延迟被内核切换到父进程,父进程此时快速完成write操作(文件写入利用页缓存,速度远快于终端输出),之后才切回子进程执行它的write。这就会出现“子进程先打印,但父进程先写入文件”的现象。

2. 特定环境下的调度规律性

虽然理论上进程调度是随机的,但在负载较低的系统中,内核的调度行为会呈现出一定的规律:

  • fork()会复制父进程的资源,内核为了避免父进程继续执行干扰子进程的资源复制工作,通常会优先调度子进程启动。
  • 但子进程的printf涉及终端交互,终端I/O的处理延迟相对较高,内核会在此时切换回父进程执行;而父进程的write操作仅需写入内存页缓存,几乎没有延迟,因此父进程的write会先完成。
  • 这种规律在相同环境、低负载下会重复出现,导致你每次运行都看到文件内容为"ba"。

3. 共享文件描述符的影响

由于open是在fork之前调用的,父子进程共享同一个文件描述符对应的文件表项,其中包括共享的文件偏移量:

  • 无论哪个进程先执行write,都会将文件偏移量向后移动1位;另一个进程的write会接着写入下一个位置,不会出现内容覆盖。
  • 文件内容为"ba",说明父进程的write总是先修改了文件偏移量,因此'b'被写入文件起始位置,'a'被写入第二个位置。

4. 为何无需wait()也有稳定结果?

wait()的作用是强制父进程等待子进程退出,保证子进程的操作全部完成后父进程再继续执行。但你的场景中,没有wait()却出现稳定结果,只是特定环境下的巧合:

  • 这种固定顺序不具备跨系统通用性,如果在高负载系统或采用不同调度算法的内核中运行,完全可能出现文件内容为"ab"的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 00:31:03