【Linux】多线程中使用fork()
(最核心的東西我在下面用紅色字體標出來了,理解了那塊,這些東西都是就理解了!)
在本篇文章開始之前,需要大家先了解線程和進程,這位大哥講的言簡意賅:進程和線程的主要區別(總結)_kuangsonghan的博客-CSDN博客_進程與線程的區別
如標題所示,如果在多線程中的某一個線程中使用fork函數之后,fork產生的子進程會不會復制父進程中的線程呢?
答案是不會的,fork的時候只復制當前線程到子進程,下面是fork的描述:
fork(2): create child process - Linux man page
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.
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.
下面我們來看一下下面這個例子:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/wait.h>pthread_mutex_t mutex; //互斥鎖的創建void * fun(void * arg)
{pthread_mutex_lock(&mutex);printf("fun lock \n");sleep(5);pthread_mutex_unlock(&mutex);printf("fun unlock \n");
} int main()
{pthread_mutex_init(&mutex,NULL);pthread_t id;pthread_create(&id,NULL,fun,NULL);sleep(1);pid_t pid = fork();if(pid == -1){exit(0);}if(pid == 0){printf("child will lock \n");pthread_mutex_lock(&mutex);printf("chile lock \n");pthread_mutex_unlock(&mutex);printf("child umlock \n");exit(0);}wait(NULL);printf("main end \n");exit(0);
}
上述代碼中整體的邏輯? 我來給大家理一下,先開始是主線程創建了子線程,然后子線程中啥也不干,加鎖----輸出fun lock------睡眠五秒鐘------解鎖-----輸出fun unlock
等不到子線程執行完,主線程又執行了fork命令,將主線程復制一份到子進程中,這會的主線程也充當了子進程的父進程,因為所有線程共享一把鎖,這會子線程中的鎖還在枷鎖狀態中,所以子進程中也就被fork將鎖的加鎖狀態鎖給復制到了子進程中,
這時候到了子進程中的時候,子進程首先打印出child will lock 然后準備加鎖的時候發現,鎖是夾著的狀態,所以就一直會阻塞在子進程中加鎖的那一步,ok,整體梳理了一遍,我們來看上述代碼的運行結果:
?和我上述理的思路一毛一樣,最后程序一直阻塞到了子進程中加鎖那步,那么這種情況怎么解決呢?
首先我們在fork的時候,我們不清楚鎖的狀態,所以才會造成上面的問題出現,所以我們必須在fork的時候就清楚鎖的狀態:
其實在Linux中人家已經幫我們寫好了,他就是:pthread_atfork
atfork() --同步父子進程 pthread_mutex_lock加解鎖問題_Turbyun的博客-CSDN博客
pthread_atfork(void (*prepare)(void),void (*parent)(void), void(*child)(void))
?該函數中的三個參數都是指向函數的指針
第一個參數是在調用fork之前該調用的函數
第二個參數是在調用fork之后,父進程該調用的函數
第三個參數是在調用fork之后,子進程該調用的函數
ok? ?上述參數也交代清楚了? ?那么在我們上述的代碼中這三個函數分別應該怎么寫那?
在調用fork之前應該調用的函數:對互斥鎖的加鎖
void before_fork()
{pthread_mutex_lock(&mutex);
}
在調用fork之后應該調用的函數:對互斥鎖的解鎖
void after_fork()
{pthread_mutex_unlock(&mutex);
}
這時候 我們已經清楚鎖的狀態了,這種也就是清楚鎖的狀態的時候,fork才會進程執行,也就是推遲fork執行的時間,那么加上代碼之后我們來看總代碼:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/wait.h>pthread_mutex_t mutex; //互斥鎖的創建void before_fork()
{pthread_mutex_lock(&mutex);
}void after_fork()
{pthread_mutex_unlock(&mutex);
}void * fun(void * arg)
{pthread_mutex_lock(&mutex);printf("fun lock \n");sleep(5);pthread_mutex_unlock(&mutex);printf("fun unlock \n");
} int main()
{pthread_mutex_init(&mutex,NULL);pthread_t id;pthread_create(&id,NULL,fun,NULL);sleep(1);pthread_atfork(before_fork,after_fork,after_fork); //這行代碼只要在fork之前就行pid_t pid = fork();if(pid == -1){exit(0);}if(pid == 0){printf("child will lock \n");pthread_mutex_lock(&mutex);printf("chile lock \n");pthread_mutex_unlock(&mutex);printf("child umlock \n");exit(0);}wait(NULL);printf("main end \n");exit(0);
}
然后執行的時候,fork會等待子線程解鎖之后才執行:
一般來說? 真實的代碼中不會讓子線程中sleep(5)然后再執行fork? ?這只是為了讓我們能看的更清楚,所以才加的,真實的是子線程加鎖解鎖然后fork,是很快的,肉眼根本察覺不到的!
?
“每一個不曾起舞的日子,都是對生命的辜負!”
總結
以上是生活随笔為你收集整理的【Linux】多线程中使用fork()的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 将夜人字符是谁画的啊?
- 下一篇: 复联有第5部吗?