【问题标题】:Make processes run at the same time using fork使用 fork 使进程同时运行
【发布时间】:2018-03-22 20:37:05
【问题描述】:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>


int main(int argc, char **argv) {
    FILE *file;
    file = fopen(argv[1], "r");
    char buf[600];
    char *pos;
    pid_t parent = fork();
    if(parent == 0) { 
        while (fgets(buf, sizeof(buf), file)) {
            pid_t child = fork();
            if(child == 0) {
                /* is there a function I can put here so that it waits 
                once the parent is exited to then run?*/
                printf("%s\n", buf);
                return(0);

            }

        }
        return(0);
    }
    wait(NULL);
    return(0);

}

这里的目标是同时并行打印出文件的行。

例如:

给定一个文件

a 
b
c


$ gcc -Wall above.c
$ ./a.out file
a
c
b
$ ./a.out file
b
c
a

就像在同一时间运行的进程一样。我想如果有一个等待父项退出然后开始运行子项的等待子句,我可以让它工作。如上面的 cmets 所示。一旦父进程退出,所有进程都会根据需要从 print 语句开始。

【问题讨论】:

  • 我认为我们对“在同一时间”有不同的理解。请解释一下。
  • 它们并行运行,行的顺序无关紧要,每行都是独立的。
  • 也许 threads 更适合您的目的。您必须使用流程吗?
  • 是只使用 fork 的进程
  • 这篇文章似乎回答了你的问题。 stackoverflow.com/questions/32723398/…

标签: c linux fork


【解决方案1】:

如果你有:

int i = 10;
while (i > 0)
{
    pid_t child = fork();
    if(child == 0) {
        printf("i: %d\n", i--);
        exit(0);
    }
}

然后子进程同时运行。根据内核的数量和您的操作系统调度程序,它们甚至可能同时运行。但是,printf 是缓冲区,因此无法确定行在屏幕上出现的顺序,并且会在程序执行之间有所不同。而且因为printf 是缓冲的,您很可能看不到与其他行重叠的行。但是,如果您将write 直接用于stdout,则输出可能会重叠。

然而,在你的场景中,孩子们死得如此之快,因为你正在阅读 从一个文件(可能需要一段时间才能返回),到下一个 fork 执行时, 以前的孩子已经死了。但这并不能改变事实,如果 孩子们会跑得足够长,他们会同时跑,而且 无法确定屏幕上的行顺序。

编辑

正如Barmar 在 cmets 中指出的那样,write 是原子的。我在我的 手册页和 BUGS 部分是这样说的:

man 2 写

根据 POSIX.1-2008/SUSv4 Section XSI 2.9.7(“线程与常规文件操作的交互”):

以下所有函数在对常规文件或符号链接进行操作时,在 POSIX.1-2008 中指定的效果中相互之间应该是原子的:...

随后列出的 API 包括 write()writev(2)。在应该是跨线程原子的效果中(和 pro- cesses) 是文件偏移量的更新。 但是,在 3.14 之前的 Linux 上,情况并非如此:如果两个进程共享一个 打开文件描述(见open(2))同时执行write()(或writev(2)),则I/O操作不是原子的 考虑更新文件偏移量,结果是两个进程输出的数据块可能(不正确地)重叠。 此问题已在 Linux 3.14 中修复。

几年前,我在 stdout 上观察到 write 的这种行为,并发 孩子们打印的东西,这就是为什么我用write 写的,这些行可能 重叠。

【讨论】:

  • 虽然write() 没有缓冲,但我认为每个调用都是原子的,因此它们不会重叠。如果您分别编写文本和换行符,您可能会混淆。
  • @Barmar 我的手册页确实提到 POSIX 要求 write 是原子的,但它也提到在 linux 3.14 之前情况并非如此。我知道在过去我已经看到write 在分叉进程上相互重叠的这种行为。谢谢,我会修正我的答案
  • 这实际上可能取决于写入的大小。或者它只适用于管道,PIPE_BUF 下面的写入保证是原子的。
【解决方案2】:

我不知道你为什么有一个外循环。你可以重写如下。创建子进程后,它们可以按任何顺序运行。因此,您可能会以“顺序”显示输出,但在另一次运行中,您可能会看到不同的顺序。这取决于您的操作系统的进程调度,并且为了您的目的,它都以“并行”方式运行。所以你真的不需要确保父进程已经死了。

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


int main(int argc, char **argv)
{
    if (argc != 2) {
        printf("Incorrect args\n");
        exit(1);
    }

    char buf[1024];
    FILE *file = fopen(argv[1], "r");

    while (fgets(buf, sizeof buf, file)) {
        pid_t child = fork();
        if(child == 0) {
            write(STDOUT_FILENO, buf, strlen(buf));
            _exit(0);
        }
    }

    /* Wait for all child processes. */
    while (wait(NULL) != -1);
}

【讨论】:

    猜你喜欢
    • 2022-11-02
    • 1970-01-01
    • 2021-05-11
    • 2020-02-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-18
    • 1970-01-01
    相关资源
    最近更新 更多