多執行緒環境下fork的使用以及鎖的變化

2021-09-30 16:50:45 字數 2472 閱讀 6933

關於執行緒的建立與使用,前幾個部落格說的很詳細了,那麼我們如果在某乙個函式執行緒中呼叫fork函式有什麼需要注意的嗎?

示例**:

#include#include#include#include#include#include//測試執行緒中呼叫frok的結果

void *fun(void *arg)

} else }

}int main()

pthread_exit(null);

}

執行結果:

可以看出主程序中的輸出並沒有被再次執行,只列印了5次dog,子程序的確只呼叫了使用fork的函式執行緒

子程序會繼承其父程序的鎖以及鎖的狀態,但是父子程序用的不是同一把鎖,父程序解鎖並不會影響到子程序的鎖,即fork以後子程序和父程序使用的是兩把鎖。那麼子程序就有可能死鎖,比如我們在fork之前,乙個執行緒對某個鎖進行的lock操作,即持有了該鎖,然後另外乙個執行緒呼叫了fork建立子程序。可是在子程序中持有那個鎖的執行緒卻"消失"了,從子程序的角度來看,這個鎖被「永久」的上鎖了,因為它的持有者「蒸發」了,所以如果子程序中的這個執行緒對這個已經被持有的鎖進行lock操作的話,就會發生死鎖。

可能有人會想到可以在fork之前讓呼叫fork的執行緒獲取所有的鎖,然後再在fork出的子程序的中釋放每乙個鎖。這種方法是可以的,但是這種做法會帶來乙個問題,那就是隱含了一種上鎖和解鎖的先後順序,如果次序不同,就會發生死鎖。

比如,子程序繼承來了父程序中的鎖a和鎖b,現在需要在自己的執行緒中對其解鎖(當然也是在自己的執行緒中加鎖的,我沒有畫),如果向我上面那種畫法,就會出現死鎖。因為先對a加鎖然後對b加鎖,那麼你在對b進行解鎖前應該先對a解鎖,但是對a解鎖在對b解鎖之後,所以會發生死鎖。所以這種方法很麻煩,但是有人不厭其煩說可以做到控制順序,但是這種執行緒中呼叫fork還是有很多問題是不能控制的(比如庫函式等),所以系統為我們解決了這種問題,提供給了我們乙個函式

int thread_atfork(void(*prepare)(void),void(*parent)(void),void(*child)(void));

上述並不是加鎖一次解鎖了兩次,而是各自獨自解鎖。因為子程序位址空間建立的時候,得到了所有父程序定義的鎖的副本,繼承的是父程序的鎖的拷貝。任何乙個程序修改鎖的狀態就會為另乙個程序拷貝乙份滴(寫時拷貝),所以並沒有加鎖一次解鎖兩次,這也是我上面說的父子程序用的不是同一把鎖,各自操作各自的鎖就沒有影響啦。需要注意的是pthread_atfork只能清理鎖,但不能清理條件變數。在有些系統的實現中條件變數不需要清理。但是在有的系統中,條件變數的實現中包含了鎖,這種情況就需要清理。但是目前並沒有清理條件變數的介面和方法。測試用例:

#include#include#include#include#include#include//使用pthread_atfork函式進行獲取鎖

pthread_mutex_t mutex;

void *fun(void *arg)

void prepare() //pthread_atfork一旦被呼叫就會執行該函式,但是需要等待fun釋放鎖才可以將鎖加上

指定在fork呼叫之前,建子程序之前,呼叫prepare函式,獲取所有的鎖,然後建立子程序,子程序建立以後,父程序環境中呼叫parent所有的鎖,子程序環境中呼叫child解所有的鎖,然後fork函式再返回。這樣保證了fork之後,子程序拿到的鎖都是解鎖狀態,避免死鎖。

記錄一下c 中,多執行緒中的使用,以及例項

include include include include include include using std cout using std cin using std endl using std string using std initializer list using namespac...

linux下多執行緒中的fork介紹

目錄 回想一下 當乙個程式只有主線程的時候呼叫fork,此時fowww.cppcns.comrk會建立出的子程序也會只有一條執行緒 那要是把fork放入多執行緒的程式中呢?我們來試驗下 include include include void pthread fun void arg int mai...

Thread 多執行緒使用以及四種建立方式

一 實現runable介面,重新run方法 1 同步 塊 模擬賣票系統 class window implements runnable catch interruptedexception e system.out.println thread.currentthread getname 票號為 ...