Linux fork()、vfork()、exec()和clone()的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4856255/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 00:15:21  来源:igfitidea点击:

The difference between fork(), vfork(), exec() and clone()

linuxprocessforkexecclone

提问by user476033

I was looking to find the difference between these four on Google and I expected there to be a huge amount of information on this, but there really wasn't any solid comparison between the four calls.

我想在谷歌上找到这四个之间的区别,我预计会有大量关于这方面的信息,但是这四个电话之间确实没有任何可靠的比较。

I set about trying to compile a kind of basic at-a-glance look at the differences between these system calls and here's what I got. Is all this information correct/am I missing anything important ?

我开始尝试编译一种基本的概览,看看这些系统调用之间的差异,这就是我得到的。所有这些信息是否正确/我是否遗漏了任何重要的信息?

Fork: The fork call basically makes a duplicate of the current process, identical in almost every way (not everything is copied over, for example, resource limits in some implementations but the idea is to create as close a copy as possible).

Fork:fork 调用基本上复制了当前进程,几乎在所有方面都相同(并非所有内容都被复制,例如,某些实现中的资源限制,但其想法是创建尽可能接近的副本)。

The new process (child) gets a different process ID (PID) and has the the PID of the old process (parent) as its parent PID (PPID). Because the two processes are now running exactly the same code, they can tell which is which by the return code of fork - the child gets 0, the parent gets the PID of the child. This is all, of course, assuming the fork call works - if not, no child is created and the parent gets an error code.

新进程(子进程)获得不同的进程 ID (PID),并将旧进程(父进程)的 PI​​D 作为其父进程 PID (PPID)。因为这两个进程现在运行完全相同的代码,他们可以通过 fork 的返回码来判断哪个是哪个 - 子进程为 0,父进程得到子进程的 PID。当然,假设 fork 调用有效,这就是全部 - 如果没有,则不会创建子级,父级会收到错误代码。

Vfork: The basic difference between vfork and fork is that when a new process is created with vfork(), the parent process is temporarily suspended, and the child process might borrow the parent's address space. This strange state of affairs continues until the child process either exits, or calls execve(), at which point the parent process continues.

Vfork: vfork 和 fork 的基本区别在于,当使用 vfork() 创建新进程时,父进程会被暂时挂起,子进程可能会借用父进程的地址空间。这种奇怪的状态一直持续到子进程退出或调用 execve(),此时父进程继续。

This means that the child process of a vfork() must be careful to avoid unexpectedly modifying variables of the parent process. In particular, the child process must not return from the function containing the vfork() call, and it must not call exit() (if it needs to exit, it should use _exit(); actually, this is also true for the child of a normal fork()).

这意味着 vfork() 的子进程必须小心避免意外修改父进程的变量。特别是子进程一定不能从包含vfork()调用的函数中返回,也不能调用exit()(如果需要退出,应该使用_exit();其实对于子进程也是如此一个普通的 fork())。

Exec :The exec call is a way to basically replace the entire current process with a new program. It loads the program into the current process space and runs it from the entry point. exec() replaces the current process with a the executable pointed by the function. Control never returns to the original program unless there is an exec() error.

Exec :exec 调用是一种基本上用新程序替换整个当前进程的方法。它将程序加载到当前进程空间并从入口点运行它。exec() 用函数指向的可执行文件替换当前进程。除非出现 exec() 错误,否则控制永远不会返回到原始程序。

Clone :Clone, as fork, creates a new process. Unlike fork, these calls allow the child process to share parts of its execution context with the calling process, such as the memory space, the table of file descriptors, and the table of signal handlers.

Clone :Clone 作为 fork,创建了一个新进程。与 fork 不同,这些调用允许子进程与调用进程共享其执行上下文的一部分,例如内存空间、文件描述符表和信号处理程序表。

When the child process is created with clone, it executes the function application fn(arg). (This differs from fork, where execution continues in the child from the point of the original fork call.) The fn argument is a pointer to a function that is called by the child process at the beginning of its execution. The arg argument is passed to the fn function.

当使用 clone 创建子进程时,它会执行函数 application fn(arg)。(这与 fork 不同,fork 在子进程中从原始 fork 调用的点继续执行。) fn 参数是指向子进程在执行开始时调用的函数的指针。arg 参数传递给 fn 函数。

When the fn(arg) function application returns, the child process terminates. The integer returned by fn is the exit code for the child process. The child process may also terminate explicitly by calling exit(2) or after receiving a fatal signal.

当 fn(arg) 函数应用程序返回时,子进程终止。fn 返回的整数是子进程的退出代码。子进程也可以通过调用 exit(2) 或在收到致命信号后显式终止。

Information gotten form :

信息获取形式:

Thanks for taking the time to read this ! :)

感谢您抽时间阅读 !:)

采纳答案by Javier

  • vfork()is an obsolete optimization. Before good memory management, fork()made a full copy of the parent's memory, so it was pretty expensive. since in many cases a fork()was followed by exec(), which discards the current memory map and creates a new one, it was a needless expense. Nowadays, fork()doesn't copy the memory; it's simply set as "copy on write", so fork()+exec()is just as efficient as vfork()+exec().

  • clone()is the syscall used by fork(). with some parameters, it creates a new process, with others, it creates a thread. the difference between them is just which data structures (memory space, processor state, stack, PID, open files, etc) are shared or not.

  • vfork()是一个过时的优化。在良好的内存管理之前,fork()制作了父级内存的完整副本,因此非常昂贵。由于在许多情况下 afork()后跟exec(),它会丢弃当前的内存映射并创建一个新的内存映射,因此这是不必要的开销。如今,fork()不复制记忆;它只是设置为“写入时复制”,因此fork()+exec()vfork()+一样有效exec()

  • clone()是 使用的系统调用fork()。使用一些参数,它创建一个新进程,使用其他参数,它创建一个线程。它们之间的区别只是共享或不共享哪些数据结构(内存空间、处理器状态、堆栈、PID、打开的文件等)。

回答by ninjalj

  • execve()replaces the current executable image with another one loaded from an executable file.
  • fork()creates a child process.
  • vfork()is a historical optimized version of fork(), meant to be used when execve()is called directly after fork(). It turned out to work well in non-MMU systems (where fork()cannot work in an efficient manner) and when fork()ing processes with a huge memory footprint to run some small program (think Java's Runtime.exec()). POSIX has standardized the posix_spawn()to replace these latter two more modern uses of vfork().
  • posix_spawn()does the equivalent of a fork()/execve(), and also allows some fd juggling in between. It's supposed to replace fork()/execve(), mainly for non-MMU platforms.
  • pthread_create()creates a new thread.
  • clone()is a Linux-specific call, which can be used to implement anything from fork()to pthread_create(). It gives a lot of control. Inspired on rfork().
  • rfork()is a Plan-9 specific call. It's supposed to be a generic call, allowing several degrees of sharing, between full processes and threads.
  • execve()用另一个从可执行文件加载的映像替换当前的可执行映像。
  • fork()创建一个子进程。
  • vfork()是 的历史优化版本fork(),旨在在execve()之后直接调用时使用fork()。结果证明它在非 MMU 系统(fork()无法以有效方式工作)中运行良好,并且在fork()使用具有巨大内存占用的进程来运行一些小程序时运行良好(想想 Java 的Runtime.exec())。POSIX 已标准化posix_spawn()以替换后两种更现代的vfork().
  • posix_spawn()相当于 a fork()/execve(),并且还允许在两者之间进行一些 fd 杂耍。它应该取代fork()/execve(),主要用于非 MMU 平台。
  • pthread_create()创建一个新线程。
  • clone()是 Linux 特定的调用,可用于实现从fork()到 的任何内容pthread_create()。它提供了很多控制权。灵感来自rfork().
  • rfork()是 Plan-9 特定调用。它应该是一个通用调用,允许在完整进程和线程之间进行多种程度的共享。

回答by Raj Kannan B.

in fork(), either child or parent process will execute based on cpu selection.. But in vfork(), surely child will execute first. after child terminated, parent will execute.

在 fork() 中,子进程或父进程将根据 CPU 选择执行。但在 vfork() 中,子进程肯定会先执行。子进程终止后,父进程将执行。

回答by user991800

The fork(),vfork() and clone() all call the do_fork() to do the real work, but with different parameters.

fork()、vfork() 和clone() 都调用do_fork() 来做真正的工作,只是参数不同。

asmlinkage int sys_fork(struct pt_regs regs)
{
    return do_fork(SIGCHLD, regs.esp, &regs, 0);
}

asmlinkage int sys_clone(struct pt_regs regs)
{
    unsigned long clone_flags;
    unsigned long newsp;

    clone_flags = regs.ebx;
    newsp = regs.ecx;
    if (!newsp)
        newsp = regs.esp;
    return do_fork(clone_flags, newsp, &regs, 0);
}
asmlinkage int sys_vfork(struct pt_regs regs)
{
    return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, &regs, 0);
}
#define CLONE_VFORK 0x00004000  /* set if the parent wants the child to wake it up on mm_release */
#define CLONE_VM    0x00000100  /* set if VM shared between processes */

SIGCHLD means the child should send this signal to its father when exit.

For fork, the child and father has the independent VM page table, but since the efficiency, fork will not really copy any pages, it just set all the writeable pages to readonly for child process. So when child process want to write something on that page, an page exception happen and kernel will alloc a new page cloned from the old page with write permission. That's called "copy on write".

对于fork,子进程和父进程有独立的VM页表,但是考虑到效率,fork不会真正复制任何页,它只是将子进程的所有可写页设置为只读。因此,当子进程想要在该页面上写入内容时,会发生页面异常,内核将分配一个从具有写入权限的旧页面克隆的新页面。这就是所谓的“写时复制”。

For vfork, the virtual memory is exactly by child and father---just because of that, father and child can't be awake concurrently since they will influence each other. So the father will sleep at the end of "do_fork()" and awake when child call exit() or execve() since then it will own new page table. Here is the code(in do_fork()) that the father sleep.

对于vfork来说,虚拟内存正是孩子和父亲的——正因为如此,父亲和孩子不能同时醒来,因为他们会相互影响。因此,父亲将在“do_fork()”结束时睡觉,并在孩子调用 exit() 或 execve() 时醒来,因为那时它将拥有新的页表。这是父亲睡觉的代码(在 do_fork() 中)。

if ((clone_flags & CLONE_VFORK) && (retval > 0))
down(&sem);
return retval;

Here is the code(in mm_release() called by exit() and execve()) which awake the father.

这是唤醒父亲的代码(在由 exit() 和 execve() 调用的 mm_release() 中)。

up(tsk->p_opptr->vfork_sem);

For sys_clone(), it is more flexible since you can input any clone_flags to it. So pthread_create() call this system call with many clone_flags:

对于 sys_clone(),它更灵活,因为您可以向其输入任何 clone_flags。所以 pthread_create() 用许多 clone_flags 调用这个系统调用:

int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM);

int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGNAL | CLONE_SETTLS | CLONE_PARENT_SETTID | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM);

Summary: the fork(),vfork() and clone() will create child processes with different mount of sharing resource with the father process. We also can say the vfork() and clone() can create threads(actually they are processes since they have independent task_struct) since they share the VM page table with father process.

总结:fork()、vfork() 和 clone() 将创建与父进程共享资源数量不同的子进程。我们也可以说 vfork() 和 clone() 可以创建线程(实际上它们是进程,因为它们具有独立的 task_struct),因为它们与父进程共享 VM 页表。

回答by ZarathustrA

  1. fork()- creates a new child process, which is a complete copy of the parent process. Child and parent processes use different virtual address spaces, which is initially populated by the same memory pages. Then, as both processes are executed, the virtual address spaces begin to differ more and more, because the operating system performs a lazy copying of memory pages that are being written by either of these two processes and assigns an independent copies of the modified pages of memory for each process. This technique is called Copy-On-Write (COW).
  2. vfork()- creates a new child process, which is a "quick" copy of the parent process. In contrast to the system call fork(), child and parent processes share the same virtual address space. NOTE! Using the same virtual address space, both the parent and child use the same stack, the stack pointer and the instruction pointer, as in the case of the classic fork()! To prevent unwanted interference between parent and child, which use the same stack, execution of the parent process is frozen until the child will call either exec()(create a new virtual address space and a transition to a different stack) or _exit()(termination of the process execution). vfork()is the optimization of fork()for "fork-and-exec" model. It can be performed 4-5 times faster than the fork(), because unlike the fork()(even with COW kept in the mind), implementation of vfork()system call does not include the creation of a new address space (the allocation and setting up of new page directories).
  3. clone()- creates a new child process. Various parameters of this system call, specify which parts of the parent process must be copied into the child process and which parts will be shared between them. As a result, this system call can be used to create all kinds of execution entities, starting from threads and finishing by completely independent processes. In fact, clone()system call is the base which is used for the implementation of pthread_create()and all the family of the fork()system calls.
  4. exec()- resets all the memory of the process, loads and parses specified executable binary, sets up new stack and passes control to the entry point of the loaded executable. This system call never return control to the caller and serves for loading of a new program to the already existing process. This system call with fork()system call together form a classical UNIX process management model called "fork-and-exec".
  1. fork()- 创建一个新的子进程,它是父进程的完整副本。子进程和父进程使用不同的虚拟地址空间,最初由相同的内存页填充。然后,随着两个进程的执行,虚拟地址空间开始越来越不同,因为操作系统对这两个进程中的任何一个正在写入的内存页面执行延迟复制,并分配修改页面的独立副本每个进程的内存。这种技术称为写时复制 (COW)。
  2. vfork()- 创建一个新的子进程,它是父进程的“快速”副本。与系统调用相反fork(),子进程和父进程共享相同的虚拟地址空间。笔记!使用相同的虚拟地址空间,父和子都使用相同的堆栈,堆栈指针和指令指针,就像经典fork()! 为了防止使用相同堆栈的父进程和子进程之间发生不必要的干扰,父进程的执行被冻结,直到子进程调用exec()(创建新的虚拟地址空间并转换到不同的堆栈)或_exit()(终止进程执行) )。vfork()fork()对“fork-and-exec”模型的优化。它的执行速度比 快 4-5 倍fork(),因为与fork()(即使考虑到 COW),vfork()系统调用的实现也不包括创建新地址空间(新页目录的分配和设置)。
  3. clone()- 创建一个新的子进程。此系统调用的各种参数,指定父进程的哪些部分必须复制到子进程中,哪些部分将在它们之间共享。因此,该系统调用可用于创建各种执行实体,从线程开始,到完全独立的进程结束。事实上,clone()系统调用是系统调用pthread_create()和所有fork()系统调用家族实现的基础。
  4. exec()- 重置进程的所有内存,加载和解析指定的可执行二进制文件,设置新堆栈并将控制权传递给加载的可执行文件的入口点。这个系统调用永远不会将控制权返回给调用者,并用于将新程序加载到已经存在的进程中。这个系统调用与fork()系统调用一起形成了一个经典的 UNIX 进程管理模型,称为“fork-and-exec”。