当前位置: 首页 > 面试题库 >

fork()内部调用clone()是否正确?

鲜于岳
2023-03-14
问题内容

我在这里读到,clone()系统调用用于在Linux中创建线程。现在,语法的clone()是这样的,就需要启动程序/函数地址传递给它。

但是在此页面上,此内容是内部fork()调用的clone()。所以我的问题是,由子程序创建的子进程如何fork()开始运行fork()调用后的代码部分,即它如何不需要以函数为起点?

如果我提供的链接信息不正确,请引导我找到一些更好的链接/资源。

谢谢


问题答案:

对于此类问题,请始终阅读源代码。

从glibc
nptl/sysdeps/unix/sysv/linux/fork.c(GitHub)(nptl=
Linux的本地Posix线程)中,我们可以找到的实现fork(),它绝对 不是
syscall,我们可以看到魔术发生在ARCH_FORK宏内部,该宏定义为clone()in
nptl/sysdeps/unix/sysv/linux/x86_64/fork.c(GitHub)的内联调用。但是,等等,没有函数或堆栈指针传递给此版本的clone()!那么,这是怎么回事?


clone()接下来,让我们看一下glibc
中的实现。在sysdeps/unix/sysv/linux/x86_64/clone.S(GitHub)中。您可以看到它的作用是将函数指针保存在孩子的堆栈上,调用clone
syscall,然后新进程将读取从堆栈弹出的函数,然后对其进行调用。

所以它是这样的:

clone(void (*fn)(void *), void *stack_pointer)
{
    push fn onto stack_pointer
    syscall_clone()
    if (child) {
        pop fn off of stack
        fn();
        exit();
    }
}

而且fork()是…

fork()
{
    ...
    syscall_clone();
    ...
}

摘要

实际的clone()syscall不接受函数参数,它只是从返回点继续,就像fork()。因此clone()和和fork() 库函数
都是clone()syscall的包装器。

文献资料

我的手册副本是关于clone()库函数和系统调用的事实的一些预告。但是,我确实clone()在第2节中找到了误导,而不是在第2节和第3节中都发现了这种误解。

#include <sched.h>

int clone(int (*fn)(void *), void *child_stack,
          int flags, void *arg, ...
          /* pid_t *ptid, struct user_desc *tls, pid_t *ctid */ );

/* Prototype for the raw system call */

long clone(unsigned long flags, void *child_stack,
          void *ptid, void *ctid,
          struct pt_regs *regs);

和,

该页面同时描述了glibc clone() 包装函数和它所基于的基础系统调用。正文描述了包装函数;原始系统调用的差异将在本页尾进行描述。

最后,

原始clone()系统调用更紧密地对应fork(2)于子调用中的子进程继续执行。这样,将clone()省略包装函数的fn和arg参数。此外,参数顺序也会改变。



 类似资料:
  • 问题内容: 在 UNIX到Windows移植词典HPC 页的叉()这是写 没有与Unix fork()或vfork()等效的Windows API。用于基于Unix的应用程序的Microsoft子系统(SUA或Interix)是一个Unix环境,具有正确实现的fork()和vfork()。 在页面的后面还有使用标准Win32 API 函数的示例源代码。 我糊涂了。 该示例不应该使用fork()来说

  • 问题内容: 我一直想在Google上找到这四个之间的区别,我希望这方面会有大量的信息,但是这四个调用之间确实没有任何可靠的比较。 我着手尝试汇编一下这些系统调用之间的区别的基本概况,这就是我得到的。所有这些信息是否正确/我是否缺少任何重要信息? :fork调用基本上是对当前过程进行复制,几乎在所有方面都相同(例如,并非在某些实现中都复制了所有内容,例如,在某些实现中资源有限,但其想法是创建尽可能近

  • 问题内容: 我是这方面的初学者。 我研究过,,和并行线程。 我注意到,这将创建一个线程,这比使用创建新进程要少。另外,线程将与父进程共享文件描述符,内存等。 但是,当是和比并行线程更好?您能举个真实的例子给我解释一下吗? 提前致谢。 问题答案: (和公司)的优缺点是,他们创建了一个新流程,该流程是现有流程的克隆。 正如您所指出的那样,这是一个弱点,因为创建新流程会产生相当大的开销。这也意味着进程之

  • 这个包的主要用途就是在 API 内部执行请求。它允许你在可用的 API 基础上构建你的应用。内部请求也可以返回原始数据,而不是原始响应对象,这意味着你可以获得与之相关的所有语法糖。 我们需要构建一个分发器实例来发起内部请求。 $dispatcher = app('Dingo\Api\Dispatcher'); 我们现在可以用标准的 HTTP 进行内部请求. Route::get('/', func

  • #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> int main(void) { pid_t pid; pid = fork(); if (pid < 0) { exit(1); } else if (pid > 0

  • 问题内容: 如果我有一个内部类声明,例如: 其次是: A $ B内部类也将被加载吗?如果B内部类未声明为“静态”怎么办? 问题答案: 一旦代码被编译, 就没有内部类之类的东西 。如果查看的结果,则会看到两个文件: 因此,类在加载时不会加载,只是 碰巧 在中定义了。 编辑 例如,鉴于这两个文件, 和一个文件(为方便起见): 首先,通过运行进行构建。然后,解压缩生成的JAR文件(位于中): 打开每个文