問題
在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函數。