fork()、vfork()、exec() 和clone() 之间的区别

发布于 2024-10-15 02:19:59 字数 2094 浏览 3 评论 0原文

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

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

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

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

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

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

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

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

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

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

信息来自:

感谢您花时间阅读本文! :)

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).

The new process (child) gets a different process ID (PID) and has 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.

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.

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()).

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.

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.

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.

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.

Information gotten from:

Thanks for taking the time to read this ! :)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

栀子花开つ 2024-10-22 02:19:59
  • vfork() 是一种过时的优化。在良好的内存管理之前,fork() 会复制父内存的完整副本,因此成本相当昂贵。因为在许多情况下,fork() 后面跟着 exec(),它会丢弃当前的内存映射并创建一个新的内存映射,因此这是一种不必要的开销。如今,fork() 不复制内存;而是复制内存。它只是设置为“写时复制”,因此 fork()+exec()vfork()+一样高效>exec().

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

  • 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.

尬尬 2024-10-22 02:19:59
  • execve() 将当前可执行映像替换为从可执行文件加载的另一个映像。
  • fork() 创建一个子进程。
  • vfork()fork() 的历史优化版本,旨在在 fork 之后直接调用 execve() 时使用()。事实证明,它在非 MMU 系统(其中 fork() 无法以有效方式工作)中以及当 fork() 具有巨大内存占用的进程时运行良好。运行一些小程序(想想Java的Runtime.exec())。 POSIX 已经标准化了 posix_spawn() 来取代 vfork() 的后两个更现代的用法。
  • posix_spawn() 相当于 fork()/execve(),并且还允许在两者之间进行一些 fd 处理。它应该取代 fork()/execve(),主要用于非 MMU 平台。
  • pthread_create() 创建一个新线程。
  • clone() 是 Linux 特定的调用,可用于实现从 fork()pthread_create() 的任何内容。它提供了很多控制权。受到 rfork() 的启发。
  • rfork() 是 Plan-9 特定的调用。它应该是一个通用调用,允许在完整进程和线程之间进行多种程度的共享。
  • 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.
九八野马 2024-10-22 02:19:59
  1. fork() - 创建一个新的子进程,它是父进程的完整副本。子进程和父进程使用不同的虚拟地址空间,该空间最初由相同的内存页填充。然后,随着两个进程的执行,虚拟地址空间开始越来越不同,因为操作系统对这两个进程中的任何一个正在写入的内存页面执行惰性复制,并为已修改页面分配独立的副本。每个进程的内存。这种技术称为写入时复制 (COW)。
  2. vfork() - 创建一个新的子进程,它是父进程的“快速”副本。与系统调用fork()相反,子进程和父进程共享相同的虚拟地址空间。笔记!使用相同的虚拟地址空间,父级和子级都使用相同的堆栈、堆栈指针和指令指针,就像经典的 fork() 的情况一样!为了防止使用相同堆栈的父进程和子进程之间发生不必要的干扰,父进程的执行将被冻结,直到子进程调用 exec() (创建新的虚拟地址空间并转换到不同的堆栈)或_exit()(终止进程执行)。 vfork()fork() 针对“fork-and-exec”模型的优化。它的执行速度比 fork() 快 4-5 倍,因为与 fork() 不同(即使牢记 COW),的实现vfork()系统调用不包括新地址空间的创建(新页目录的分配和设置)。
  3. clone() - 创建一个新的子进程。该系统调用的各种参数指定父进程的哪些部分必须复制到子进程中以及子进程之间共享哪些部分。因此,该系统调用可用于创建各种执行实体,从线程开始,到完全独立的进程结束。事实上,clone() 系统调用是用于实现pthread_create() 和所有fork() 系列的基础。 > 系统调用。
  4. exec() - 重置进程的所有内存,加载并解析指定的可执行二进制文件,设置新堆栈并将控制权传递给已加载可执行文件的入口点。该系统调用永远不会将控制权返回给调用者,而是用于将新程序加载到已存在的进程中。该系统调用与fork()系统调用一起构成了一个经典的UNIX进程管理模型,称为“fork-and-exec”。
  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".
征棹 2024-10-22 02:19:59

fork()、vfork() 和clone() 都调用do_fork() 来完成实际工作,但参数不同。

asmlinkage int sys_fork(struct pt_regs regs)
{
    return do_fork(SIGCHLD, regs.esp, ®s, 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, ®s, 0);
}
asmlinkage int sys_vfork(struct pt_regs regs)
{
    return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 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.

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

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

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

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

up(tsk->p_opptr->vfork_sem);

对于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);

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

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

asmlinkage int sys_fork(struct pt_regs regs)
{
    return do_fork(SIGCHLD, regs.esp, ®s, 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, ®s, 0);
}
asmlinkage int sys_vfork(struct pt_regs regs)
{
    return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.esp, ®s, 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".

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.

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.

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:

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.

梦在深巷 2024-10-22 02:19:59

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

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文