0

我是编程过程的新手,我的基本程序并没有像我预期的那样工作。我在 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

谢谢!

4

2 回答 2

1

打印 5 个字符串发生得太快了,父进程在子进程开始自己的循环之前完成了它的循环。尝试更多循环,500 Works For Me™。

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


其他问题。

你得到了--end of program--两次,因为子进程没有退出。一旦它完成了它的循环,它就会继续运行其余的代码。exit(0)给孩子添加一个。

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

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

--beginning of program如果输出到管道或文件,例如./program | cator ,您可以获得两次./program > output。因为 I/O 缓冲。

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

无缓冲就是它所说的,你调用printf它并发送它。stderr通常是无缓冲的,因为在错误发生时看到错误很重要。

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

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

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

因为stdout是行缓冲区,所以结果将是SecondFirstThird.

除非 stdoutstderr不去码头。如果他们要去管道或文件,他们可能是块缓冲的。这意味着输出将被缓冲,直到看到一定数量的数据,然后将其刷新。

在您的代码中, if stdoutis line bufferedprintf("--beginning of program\n");会立即刷新。但是如果stdout被重定向到一个文件,它会被块缓冲并且不会立即写入。"--beginning of program\n"仍在stdout's 缓冲区中。当你 fork 时,孩子会获得该缓冲区的副本并将其添加到其中。所以孩子和父母都 print "--beginning of program\n"

您可以通过在使用fflush.

    printf("--beginning of program\n");
    fflush(stdout);
于 2020-11-06T21:19:54.680 回答
0

使用当前代码,您获得的输出将因机器而异。例如,当我运行代码时,进程调度程序决定先运行父进程,然后再运行子进程,然后再返回父进程,然后来回运行,直到它们都完成。

见附图。

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;
}
于 2020-11-06T21:19:28.250 回答