乐闻世界logo
搜索文章和话题

Fork 、 vfork 、exec 和clone 之间的区别

4 个月前提问
4 个月前修改
浏览次数7

1个答案

1

在 Linux 系统编程中,fork()vfork()exec()clone() 都是用于进程控制的系统调用,但它们的用途和行为有所不同。

1. fork()

fork() 用于创建一个新的进程,称为子进程,它是调用进程的副本。它复制了父进程的所有内存空间、打开的文件描述符等资源。父进程和子进程将从 fork() 调用后的下一条指令开始执行。

例子

c
#include <stdio.h> #include <unistd.h> int main() { pid_t pid = fork(); if (pid == 0) { // 子进程执行的代码 printf("This is child process\n"); } else { // 父进程执行的代码 printf("This is parent process\n"); } return 0; }

2. vfork()

vfork() 也是用来创建子进程的,但它和 fork() 有所不同。vfork() 创建的子进程共享父进程的地址空间(不立即复制整个地址空间)。子进程会先运行,在它调用 exec()exit() 之后父进程才可能被调度运行。vfork() 主要用于子进程很快就要调用 exec()exit() 的情况,这样可以避免不必要的地址空间复制。

例子

c
#include <stdio.h> #include <unistd.h> #include <stdlib.h> int main() { pid_t pid = vfork(); if (pid == 0) { // 子进程执行的代码 printf("This is child process\n"); _exit(0); // 注意,这里使用 _exit() 而不是 exit() } else { // 父进程执行的代码 printf("This is parent process\n"); } return 0; }

3. exec()

exec() 系列函数用于在当前进程中执行一个新的程序。它将当前进程的地址空间替换为新程序的地址空间,但进程ID不变。exec() 常在 fork()vfork() 之后调用,以在子进程中运行新程序。

例子

c
#include <stdio.h> #include <unistd.h> int main() { pid_t pid = fork(); if (pid == 0) { // 子进程执行的代码 execlp("ls", "ls", NULL); } else { // 父进程继续执行 wait(NULL); // 等待子进程结束 } return 0; }

4. clone()

clone() 是比 fork() 更为灵活的进程创建方式。它允许调用者指定父进程和子进程共享的资源种类,如文件描述符、地址空间等。通过传递不同的标志位,可以实现类似 fork()vfork() 或线程(轻量级进程)的行为。

例子

c
#define _GNU_SOURCE #include <stdio.h> #include <sched.h> #include <unistd.h> #include <sys/wait.h> int child_func(void* arg) { printf("This is child process\n"); return 0; } int main() { const int STACK_SIZE = 65536; // 栈大小 char* stack = malloc(STACK_SIZE); if (!stack) { perror("Failed to allocate stack"); exit(1); } unsigned long flags = CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM; pid_t pid = clone(child_func, stack + STACK_SIZE, flags, NULL); waitpid(pid, NULL, 0); free(stack); return 0; }

这些系统调用是操作系统的基础,非常重要。希望这些解释和例子能帮助您理解它们之间的区别。

2024年8月22日 16:31 回复

你的答案