【问题标题】:fork() execution processfork() 执行过程
【发布时间】:2011-06-27 23:27:19
【问题描述】:

fork() 究竟是如何工作的?

以下代码

#include <stdio.h>

int main (int argc, char const *argv[])
{
printf("Hi\n");
int i;
for(i = 1; i < argc; i++)
{
    printf("Argument %d is %s\n", i, argv[i]);
    fork();
    printf("Forked in for loop increment %d\n", i);
}


return 0;
}

给出以下输出

/a.out 你好世界

参数 1 是你好

fork 循环增量 1

参数 2 是世界

fork 循环增量 2

fork 循环增量 1

参数 2 是世界

fork 循环增量 2

fork 循环增量 2

一般来说,fork 先执行什么代码。我想知道 fork() 的原理,而不是仅仅基于这个例子。我可以在命令行上有多个参数。

【问题讨论】:

    标签: c fork


    【解决方案1】:

    请注意,进程的数量将呈指数增长,因此对于 100 个参数,我们谈论的是 1267650600228229401496703205376 个进程。我希望你有一台非常强大的电脑:)。

    我会在这里回答你的评论,它可能会帮助你理解分叉。

    在每个循环之后,您将加倍进程数。因此,在 N 个循环之后,您将得到 2^N 个过程。或者在 100 次循环之后,你会得到我给你的那个大数字。

    顺便说一句,fork bombs 是最常见的 DoS 攻击之一 :)

    【讨论】:

    • 这太夸张了。 ;) 你是怎么得到那个数字的?
    • 每个参数都会使分叉进程的数量翻倍。所以你最终会得到 2^n 个进程。很长一段时间以来,大多数操作系统一次无法管理超过 2^16 个进程,因为进程 ID (PID) 曾经是一个 16 位数字。即使今天的操作系统主要使用 32 位类型的 PID,通常也有 2^16 的限制。但很少有人一次在一个系统上产生超过 1000 个进程。
    • 感谢您的信息。 @Klark:叉子炸弹链接很有趣,谢谢。
    【解决方案2】:

    fork 是系统调用,即调用内核的库例程。在为fork 调用提供服务时,内核会创建一个新进程,该进程执行与调用它的进程相同的程序。新进程开始执行,就好像 it 调用了fork;返回值与父级中的不同,所以可以区分两者。

    调用fork 的常用习语是:

    pid_t pid = fork();
    
    switch (pid) {
      case -1:
        /* an error occurred, i.e. no child process created */
        handle_error();
      case 0:
        /* a return value of 0 means we're in the child process */
        do_child_stuff();
        break;  // or _exit()
      default:
        /* we're in the parent; pid is the child's process id */
        do_parent_stuff();
    }
    

    如何 其工作原理是:操作系统对调用 fork 的进程进行了近乎完美的复制(PID 和其他一些值不同,但内存内容开始时几乎相同,并且通常在两者中打开相同的文件)。复制通常使用所谓的写时复制 (COW) 语义完成,因此在其中一个进程开始分配变量之前几乎不会进行任何实际复制。

    【讨论】:

    • 所以我的打印输出误导了我。 for 循环中的 fork() 很奇怪吧?
    • 程序中的输出顺序是不确定的。循环中的fork 并不奇怪(您可能想要创建一些 n 数量的工作进程),但是子进程和父进程运行相同代码的裸 fork 非常罕见.大多数时候,fork 只是为调用exec 做准备。
    • @Helium3 奇怪的是代码不会将 fork 的返回值存储在一个名为 childpid 之类的变量中,然后根据它是否为 0(在孩子中)、正数来做不同的事情(在父母中)或否定(失败)。这可以循环发生,也可以不循环。
    • 如何使用这些 pid?在上面的开关中,人们会知道会执行什么,因为 pid_t pid = fork();返回特定的pid,或者为什么返回的pid可能是孩子或父母?之后如何根据需要使用 pid?是否可以在 pid 上使用一些库函数,例如(在这里猜测一下)sleep() 或 kill()。分叉的进程能否为一定数量的所需进程递归地创建分叉进程并从主父进程中跟踪它们?
    • @Helium3:请阅读switch 中的cmets。如果 pid 为零,我们在孩子中并且我们执行“童工”。否则我们在父节点中,我们(可能)以某种方式控制子节点,向它提供数据,并最终wait 让它退出。我从未见过叉炸弹之外的递归分叉,也看不到它有任何用处。它只会设置不必要的进程等待他们的孩子执行工作。简单的循环更简单、更高效。
    猜你喜欢
    • 2013-09-25
    • 2019-02-22
    • 2013-01-14
    • 2014-06-17
    • 2015-04-28
    • 1970-01-01
    • 2022-01-05
    • 1970-01-01
    • 2017-09-22
    相关资源
    最近更新 更多