我想在谷歌上找到这四个之间的区别,我希望在这方面有大量的信息,但这四个调用之间真的没有任何可靠的比较。
我开始尝试编译一种基本的概览,看看这些系统调用之间的差异,下面是我得到的结果。这些信息都正确吗/我遗漏了什么重要的东西吗?
Fork: Fork调用基本上创建了当前进程的副本,几乎在所有方面都是相同的(并非所有内容都被复制,例如,在某些实现中存在资源限制,但其想法是创建尽可能接近的副本)。
新进程(子进程)获得不同的进程ID (PID),并将旧进程(父进程)的PID作为其父PID (PPID)。因为两个进程现在正在运行完全相同的代码,它们可以通过fork的返回代码来区分哪个是哪个——子进程得到0,父进程得到子进程的PID。当然,这只是假设fork调用有效的情况——如果不行,就不会创建子进程,父进程会得到一个错误代码。
Vfork: Vfork()和fork()之间的基本区别是,当用Vfork()创建一个新进程时,父进程会暂时挂起,子进程可能会借用父进程的地址空间。这种奇怪的状态一直持续到子进程退出或调用execve(),此时父进程退出
过程仍在继续。
这意味着vfork()的子进程必须小心避免意外地修改父进程的变量。特别地,子进程不能从包含vfork()调用的函数返回,也不能调用exit()(如果需要退出,应该使用_exit();实际上,对于普通fork())的子节点也是如此。
Exec: Exec调用基本上是用一个新程序替换整个当前进程的一种方法。它将程序加载到当前进程空间中,并从入口点运行它。Exec()将当前进程替换为函数所指向的可执行文件。控件永远不会返回到原始程序,除非出现exec()错误。
Clone: Clone(),如fork(),创建一个新进程。与fork()不同的是,这些调用允许子进程与调用进程共享部分执行上下文,例如内存空间、文件描述符表和信号处理程序表。
当使用clone()创建子进程时,它执行函数应用程序fn(arg)(这与fork()不同,后者从原始fork()调用的点开始在子进程中继续执行。)fn参数是一个指向子进程在执行开始时调用的函数的指针。参数arg被传递给fn函数。
当fn(arg)函数应用程序返回时,子进程终止。fn返回的整数是子进程的退出码。子进程也可以通过调用exit(2)或在接收到致命信号后显式终止。
获得的信息:
fork和exec的区别
http://www.allinterview.com/showanswers/59616.html
http://www.unixguide.net/unix/programming/1.1.2.shtml
http://linux.about.com/library/cmd/blcmdl2_clone.htm
感谢你花时间阅读这篇文章!:)
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).
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).
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.
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".
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,虚拟内存完全是由子节点和父节点分配的——正因为如此,父节点和子节点不能同时唤醒,因为它们会相互影响。因此父进程将在“do_fork()”结束时睡觉,当子进程调用exit()或execve()时醒来,因为它将拥有新的页表。下面是父线程睡觉的代码(在do_fork()中)。
if ((clone_flags & CLONE_VFORK) && (retval > 0))
down(&sem);
return retval;
下面是在mm_release()中由exit()和execve()调用的唤醒父进程的代码。
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_cleard | CLONE_SYSVSEM);
总结:fork(),vfork()和clone()将创建与父进程共享资源的不同挂载的子进程。我们也可以说vfork()和clone()可以创建线程(实际上它们是进程,因为它们有独立的task_struct),因为它们与父进程共享VM页表。
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.