多執行緒程式裡盡量不使用fork
在多執行緒程式裡,在」自身以外的執行緒存在的狀態」下一使用fork的話,就可能引起各種各樣的問題.比較典型的例子就是,fork出來的子程序可能會死鎖.請不要,在不能把握問題的原委的情況下就在多執行緒程式裡fork子程序,
能引起什麼問題呢?
那看看例項吧.一執行下面的**,在子程序的執行開始處呼叫doit()時,發生死鎖的機率會很高.
void* doit(void*) ; nanosleep(&ts, 0); // 10秒
// 睡10秒
pthread_mutex_unlock(&mutex);
return 0;
}int main(void)
pthread_join(t, 0);
// 等待子執行緒結束
}
以下是說明死鎖的理由:
一般的,fork做如下事情
1. 父程序的記憶體資料會原封不動的拷貝到子程序中
2. 子程序在單執行緒狀態下被生成
在記憶體區域裡,
靜態變數mutex的記憶體會被拷貝到子程序裡
.而且,
父程序裡即使存在多個執行緒
,但它們也不會被繼承到子程序裡
. fork的這兩個特徵就是造成死鎖的原因.
譯者注: 死鎖原因的詳細解釋 ---
1. 執行緒裡的doit()先執行.
2. doit執行的時候會給互斥體變數mutex加鎖.
3. mutex變數的內容會原樣拷貝到fork出來的子程序中
(在此之前,mutex變數的內容已經被執行緒改寫成鎖定狀態
).4.
子程序再次呼叫doit的時候,在鎖定互斥體mutex的時候會發現它已經被加鎖,所以就一直等待,直到擁有該互斥體的程序釋放它(實際上沒有人擁有這個mutex鎖
).5.
執行緒的doit執行完成之前會把自己的mutex釋放,但這是的mutex和子程序裡的mutex已經是兩份記憶體.
所以即使釋放了mutex鎖也不會對子程序裡的mutex造成什麼影響.
例如,請試著考慮下面那樣的執行流程,就明白為什麼在上面多執行緒程式裡不經意地使用fork就造成死鎖了*3.
1. 在fork前的父程序中,啟動了執行緒1和2
2. 執行緒1呼叫doit函式
3. doit函式鎖定自己的mutex
4. 執行緒1執行nanosleep函式睡10秒
5. 在這兒程式處理切換到執行緒2
6. 執行緒2呼叫fork函式
7. 生成子程序
8. 這時,子程序的doit函式用的mutex處於」鎖定狀態」,而且,解除鎖定的執行緒在子程序裡不存在
9. 子程序的處理開始
10. 子程序呼叫doit函式
11. 子程序再次鎖定已經是被鎖定狀態的mutex,然後就造成死鎖
12 9 執行緒與fork
當乙個執行緒呼叫函式fork的時候,整個程序位址空間會被拷貝到子程序中,在8.3節中有提到copy on write.子程序是乙個與父程序完全不同的程序,但是如果父程序和子程序都沒有對記憶體內容進行修改,那麼該記憶體頁就可以在父程序與子程序之間進行共享。通過繼承父程序的整個位址空間,子程序也會繼承父...
多執行緒中使用fork 導致分頁
最近和同事一起處理了乙個 fuse 的大bug 首先看堆疊 core was generated by sf cluster bin pmxcfs program terminated with signal sigabrt,aborted.0 0x00007f2debdcc475 in raise...
linux下多執行緒中的fork介紹
目錄 回想一下 當乙個程式只有主線程的時候呼叫fork,此時fowww.cppcns.comrk會建立出的子程序也會只有一條執行緒 那要是把fork放入多執行緒的程式中呢?我們來試驗下 include include include void pthread fun void arg int mai...