C语言 创建子进程从文件中打印行,但最后一行消失,没有额外的n



我在编写C程序打印文件的行时遇到了一个问题。假设该文件有5行,它应该创建5个子进程。每个子进程从文件中读取一行并打印相应的行。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#define BUFSIZE 256
#define ITR 1e6
int main(int argc, char *argv[]) {
    if (argc != 2) exit(1);
    pid_t pid;
    char buffer[BUFSIZE] = { 0 };     // create buffer 
    FILE *fp = fopen(argv[1], "r"); // read file into *fp
    while (fgets(buffer, BUFSIZE, fp)) {
        pid = fork(); 
        if (pid == 0) {
            for (int j = 0; j < ITR; j++);
            printf("%sn", buffer);
            _exit(0);               // exit child 
        } 
    }
    wait(NULL);                     // wait for child to finish
    return 0;
}

原文件为

Child 1 reads this linen
Child 3 reads this linen
Child 2 reads this linen
Child 4 reads this linen

输出如下所示:

Child 1 reads this linen
n
Child 2 reads this linen
n
Child 3 reads this linen
n
Child 4 reads this linen
n

但是我不希望在两行之间有额外的n。因此,我将printf("%sn", buffer);修改为printf("%s", buffer);,这样就只有原始文件中的1个n了。但是输出变成

Child 1 reads this line
Child 2 reads this line
Child 3 reads this line

最后一行应该是Child 4 reads this line,但没有像我预期的那样打印出来。有人知道为什么会这样吗?

这里有一些你应该调查的问题:

  • 您应该使用exit(0)return 0而不是_exit(0):非标准函数_exit(),相当于linux上的_Exit(),可能无法正确刷新标准流缓冲区:

    7.22.4.5 _Exit函数
    包含未写入缓冲数据的打开流是否被刷新、关闭或删除临时文件是由实现定义的。

  • 循环for (int j = 0; j < ITR; j++);没有副作用,所以它很可能被编译器优化掉了。

  • stdout到终端默认是行缓冲的,所以printf("%sn", buffer)发出2个单独的系统调用来刷新输出到系统:

    1. 一个用于以换行符和
    2. 结尾的缓冲区内容
    3. 打开n格式字符串。

    这些系统调用可能在不同的子进程之间交错。您应该在第一个输出操作之前使用setvbuf(stdout, NULL, BUFSIZ, _IOFBF)更改缓冲方法,在本例中,在printf足够之前。

这是一个修改后的版本,你可以试试:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#define BUFSIZE 256
#define ITR 1e6
int main(int argc, char *argv[]) {
    if (argc != 2) exit(1);
    pid_t pid;
    char buffer[BUFSIZE] = { 0 };     // create buffer 
    FILE *fp = fopen(argv[1], "r"); // read file into *fp
    int lineno = 1;
    while (fp && fgets(buffer, BUFSIZE, fp)) {
        pid = fork(); 
        if (pid == 0) {
            setvbuf(stdout, NULL, BUFSIZ, _IOFBF);
            printf("%d: %sn", lineno, buffer);
            exit(0);               // exit child 
        }
        lineno++;
    }
    wait(NULL);                     // wait for child to finish
    return 0;
}

在我的系统中,每行输出都有一个额外的换行符,但不一定与输入文件的顺序相同。

相关内容

最新更新