fork不并行运行

问题描述

我是编程过程的新手,我的基本程序实际上并没有达到我的预期。我正在Oracle VM的Ubuntu 18.04上运行此代码

代码如下:

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>


int main()
{
   printf("--beginning of program\n");

    int counter = 0;
    pid_t pid = fork();

    if (pid == 0)
    {
        // child process
        int i = 0;
        for (; i < 5; ++i)
        {
            printf("child process: counter=%d\n",++counter);
        }
    }
    else if (pid > 0)
    {
        // parent process
        int j = 0;
        for (; j < 5; ++j)
        {
            printf("parent process: counter=%d\n",++counter);
        }
    }
    else
    {
        // fork Failed
        printf("fork() Failed!\n");
        return 1;
    }

    printf("--end of program--\n");

    return 0;
}

这是我总是得到的结果:

--beginning of program
parent process: counter=1
parent process: counter=2
parent process: counter=3
parent process: counter=4
parent process: counter=5
--end of program--
--beginning of program
child process: counter=1
child process: counter=2
child process: counter=3
child process: counter=4
child process: counter=5
--end of program--

这是我编译程序的命令:

gcc main.c -o main

谢谢!

解决方法

打印5个字符串的速度太快,父进程在子进程开始自己的循环之前就完成了它的循环。尝试更多循环,500个适用于我™。

请注意,父级和子级共享内存。子级将继承counter = 0,但不与其父级共享counter。他们都将独立计数。协调流程需要更先进的技术。


其他问题。

您两次获得--end of program--,因为子进程未退出。循环完成后,它将继续运行其余代码。向孩子添加exit(0)

如果您要在子进程完成后声明“结束”,请使用wait等待子进程完成。

    waitpid(pid,NULL,0);
    printf("--end of program--\n");

如果输出是管道或文件(例如--beginning of program./program | cat),则可以两次获得./program > output。由于I / O缓冲。

写入磁盘速度很慢。它不是将所有内容在打印后立即写入,而是先写入内存,然后再写入磁盘。共有三种常见的缓冲类型:无缓冲,行缓冲和块缓冲。哪种缓冲取决于您要写入的内容。

无缓冲就是它所说的,您叫printf并将其发送出去。 stderr通常没有缓冲,因为重要的是要在发生错误时及时查看。

缓冲的行将输出存储在内存中,直到看到换行符,然后发送整行。发送它称为“刷新缓冲区”。 stdout通常是行缓冲的。这是对终端在纸上实际打印一行的回溯。

这可能会导致奇怪的结果。

fprintf(stdout,"First");
fprintf(stderr,"Second");
fprintf(stdout,"Third\n");

由于stdout是行缓冲区,结果将是SecondFirstThird

除非 stdoutstderr不会进入终端。如果要转到管道或文件,则可能是块缓冲。这意味着输出将被缓冲,直到看到一定数量的数据为止,然后将其刷新。

在您的代码中,如果stdout被行缓冲printf("--beginning of program\n");被立即刷新。但是,如果stdout重定向到文件,则会对其进行块缓冲并且不会立即写入。 "--beginning of program\n"仍在stdout的缓冲区中。当您分叉时,子级将获得该缓冲区的副本并添加到该缓冲区中。因此,孩子和父母都打印"--beginning of program\n"

您可以通过在使用fflush进行分叉之前显式刷新stdout缓冲区来解决此问题。

    printf("--beginning of program\n");
    fflush(stdout);
,

您所获得的输出将根据您拥有的当前代码而有所不同。例如,当我运行代码时,流程调度程序决定先运行父流程,然后运行子流程,然后再运行到父流程,直到它们都完成。

查看所附图片。

https://imgur.com/a/rWVK7BJ

但是,在您的情况下,流程调度程序先运行父级并完成,然后运行子级并完成。

如果您希望孩子先运行,那么父母可以在父母中使用wait(&status)来确保孩子先运行。参见下面的代码。

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


int main()
{
   printf("--beginning of program\n");

    int counter = 0;
    int wait3,status;
    pid_t pid = fork();

    if (pid == 0)
    {
        // child process
        int i = 0;
        for (; i < 5; ++i)
        {
            printf("child process: counter=%d\n",++counter);
        }
    }
    else if (pid > 0)
    {
        wait3 = wait(&status);
        // parent process
        int j = 0;
        for (; j < 5; ++j)
        {
            printf("parent process: counter=%d\n",++counter);
        }
    }
    else
    {
        // fork failed
        printf("fork() failed!\n");
        return 1;
    }

    printf("--end of program--\n");

    return 0;
}