fork一个多线程进程的情况

3,603 阅读2分钟

问题

在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函数。