细说fork-vfork-pthread_create-clone
1.1 fork
特点:
- 完全复制父进程的地址空间
- 父子进程独立运行
- 返回两次(父进程返回子进程PID,子进程返回0)
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main() {pid_t pid = fork();if (pid < 0) {perror("fork failed");return 1;} else if (pid == 0) {// 子进程printf("Child process (PID: %d)\n", getpid());} else {// 父进程printf("Parent process (PID: %d), Child PID: %d\n", getpid(), pid);}return 0;
}
输出:
Parent process (PID: 413843), Child PID: 413844
Child process (PID: 413844)
1.2 vfork
特点:
- 子进程与父进程共享地址空间
- 子进程必须先调用exec或_exit
- 比fork()更高效
示例:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main() {pid_t pid = vfork();if (pid < 0) {perror("vfork failed");return 1;} else if (pid == 0) {// 子进程printf("Child process (PID: %d)\n", getpid());_exit(0); // 必须使用_exit而不是exit} else {// 父进程printf("Parent process (PID: %d), Child PID: %d\n", getpid(), pid);}return 0;
}
1.3 pthread_create
特点:
- 创建新线程而非进程
- 共享同一进程的地址空间
- 需要链接pthread库(-lpthread)
示例:
#include <stdio.h>
#include <pthread.h>void* thread_func(void* arg) {printf("New thread created\n");return NULL;
}int main() {pthread_t tid;int ret = pthread_create(&tid, NULL, thread_func, NULL);if (ret != 0) {perror("pthread_create failed");return 1;}printf("Main thread\n");pthread_join(tid, NULL); // 等待线程结束return 0;
}
1.4 clone
特点:
- 可以精细控制共享哪些资源
- 功能最强大但也最复杂
- 通常用于实现线程库
示例:
#define _GNU_SOURCE
#include <stdio.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>#define STACK_SIZE (1024 * 1024)static int child_func(void* arg) {printf("Child process (PID: %d)\n", getpid());return 0;
}int main() {char* stack = malloc(STACK_SIZE);if (!stack) {perror("malloc failed");return 1;}// 创建子进程,共享虚拟内存、文件描述符等pid_t pid = clone(child_func, stack + STACK_SIZE, CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_SIGHAND, NULL);if (pid < 0) {perror("clone failed");free(stack);return 1;}printf("Parent process (PID: %d), Child PID: %d\n", getpid(), pid);waitpid(pid, NULL, 0); // 等待子进程结束free(stack);return 0;
}
1.5 内核视角看
- 所有任务创建最终都调用
do_fork()
(内核函数) clone()
是最接近do_fork()
的用户空间接口- 其他函数都是
clone()
的包装:fork()
≈clone(SIGCHLD)
vfork()
≈clone(CLONE_VFORK | CLONE_VM | SIGCHLD)
- 线程 ≈
clone(共享大部分资源的flags)
1.6 总结
特性 | fork() | vfork() | pthread_create() | clone() |
---|---|---|---|---|
创建对象 | 进程 | 进程 | 线程 | 轻量级进程/线程 |
地址空间 | 复制 | 共享 | 共享 | 可配置 |
执行顺序 | 不确定 | 子进程先运行 | 不确定 | 可配置 |
资源开销 | 高 | 低 | 低 | 可配置 |
使用复杂度 | 简单 | 中等 | 中等 | 高 |
主要用途 | 通用进程创建 | exec前创建进程 | 多线程编程 | 高级线程/进程控制 |
选择哪种方法取决于具体需求:需要完全隔离用fork,需要快速exec用vfork,需要共享数据用线程,需要精细控制用clone。