问题
在linux系统中,我们都知道fork会产生一个调用进程的复制,创建出一个新的进程,那么如果父进程有多个线程会不会复制父进程的多个线程呢?
解答
使用man fork
指令查看手册其实就能找到答案,关键的一段如下
The child process is created with a single thread—the one that called fork(). The entire virtual address space of the parent is replicated in the child, including the states of mutexes, condition variables, and other pthreads objects; the use of pthread_atfork(3) may be helpful for dealing with problems that this can cause.
其中第一句话翻译过来就是子进程创建出来时只有一个线程,就是调用fork()函数的那个线程。
验证
我们可以用如下代码验证一下:
#include<pthread.h>
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
void * func1(void * args){
while(1){
printf("func1\n");
}
}
int main(){
pthread_t tid;
pthread_create(&tid, NULL, func1, NULL);
pid_t pid = fork();
// 子进程
if(pid==0){
int t = 5;
while(t-->0){
sleep(1);
printf("child process\n");
}
}
return 0;
}
代码执行结果如下:

可以看到子进程在等待的时候并输出"child process"的时候,父进程创建的线程的函数并没有输出。
那么如果我们不是在主线程中fork,而是在创建出的线程中fork呢?代码如下:
#include<pthread.h>
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
void * func1(void * args){
// fork()出一个子进程
pid_t pid = fork();
// 父进程退出
if(pid > 0) return NULL;
while(1){
sleep(1);
printf("func1:my pid = %d\n", getpid());
}
}
int main(){
pthread_t tid;
pthread_create(&tid, NULL, func1, NULL);
// 等待fork()完成
sleep(1);
while(1){
sleep(1);
printf("main :my pid = %d\n", getpid());
}
return 0;
}
执行结果如下:

可以看到结果中子进程只执行了fork()时所在的func1函数,而没有继续执行main函数中的指令,也证实了fork的子进程中只产生了fork所在的线程,而没有产生其它线程。
题外
我们注意手册中的这句话
The entire virtual address space of the parent is replicated in the child, including the states of mutexes, condition variables, and other pthreads objects;
也就是fork的时候会复制锁的状态,也就是说如果此时恰好某个锁被锁了,那么在fork产生的子进程中也是lock的状态。
用如下代码来验证一下:
#include<pthread.h>
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void * func1(void * args){
pthread_mutex_lock(&mutex);
printf("func1\n");
pthread_mutex_unlock(&mutex);
}
int main(){
pthread_t tid;
pthread_create(&tid, NULL, func1, NULL);
// sleep保证线程加锁完成才fork
sleep(1);
pid_t pid = fork();
// 子进程
if(pid==0){
int t = 5;
sleep(1);
while(t--){
// 子进程请求锁
pthread_mutex_lock(&mutex);
printf("child process\n");
sleep(1);
pthread_mutex_unlock(&mutex);
}
}
return 0;
}
程序执行结果:

子进程进入想要锁的状态,但是没有后续输出,原因就是fork的时候mutex被锁住了,而子进程把mutex被锁的状态复制了,而又没有其它子线程来释放锁,所以一直请求不到锁阻塞在pthread_mutex_lock函数。