這個知識點也是老生常談了,咱們今天就把他講清楚弄明白。
執行緒池是指在乙個多執行緒程式中建立乙個執行緒集合,在執行新的任務的時候不是新建乙個執行緒,而是使用執行緒池中已建立好的執行緒,一旦任務執行完畢,執行緒就會休眠等待新的任務分配下來。
這麼看來,執行緒池的優點就很明顯了,在頻繁的執行緒切換環境中,執行緒池可以省去多次執行緒的建立與釋放所需要的時間。
這個我還是稍微了解一點的。建立乙個執行緒非常簡單。
1.向核心空間申請一段記憶體用來存放新執行緒的pcb;
2.pcb中預留指標指向核心棧;
3.pcb中存放待執行執行緒函式與函式引數;
4.加入程序排程佇列或直接ret執行(需要先將函式指標放在棧頂,然後ret會將其載入到eip暫存器上,完成立刻執行執行緒操作)
簡言之,fork就是建立了乙個父程序的拷貝。
使用fork函式得到的子程序從父程序的繼承了整個程序的位址空間,包括:程序上下文、程序堆疊、記憶體資訊、開啟的檔案描述符、訊號控制設定、程序優先順序、程序組號、當前工作目錄、根目錄、資源限制、控制終端等。
子程序與父程序的區別在於:
1、父程序設定的鎖,子程序不繼承(因為如果是排它鎖,被繼承的話,矛盾了)
2、各自的程序id和父程序id不同
記住,fork是一次呼叫兩次返回值,因為會在兩個位址空間中都執行返回。
如果成功建立乙個子程序,對於父程序來說返回子程序id
如果成功建立乙個子程序,對於子程序來說返回值為0
如果為-1表示建立失敗。
fork系統呼叫複製產生的子程序與父程序(呼叫程序)基本一樣:**段+資料段+堆疊段+pcb,當前的執行環境基本一樣,所以子程序在fork之後開始向下執行,而不會從頭開始執行。
fork系統呼叫之後,父子程序將交替執行,執行順序不定。
如果父程序先退出,子程序還沒退出那麼子程序的父程序將變為init程序(託孤給了init程序)。(注:任何乙個程序都必須有父程序)
如果子程序先退出,父程序還沒退出,那麼子程序必須等到父程序捕獲到了子程序的退出狀態才真正結束,否則這個時候子程序就成為僵程序(殭屍程序:只保留一些退出資訊供父程序查詢)。殭屍程序可以在程序列表中檢視。
首先任何程序都有父程序(init程序是所有程序的祖宗,它沒有爸爸),當父程序拋棄了自己fork出來的子程序而執行完成後,子程序就被託管給init程序。
孤兒程序其實沒啥危害。
殭屍程序就不一樣了。本來吧,父程序在fork乙個子程序的時候,接下來需要wait操作等待子程序結束,然後子程序才會全部釋放資源(子程序執行完成後並沒有全部釋放資源,還剩下pid這種東西,退出狀態這種東西,必須要父程序wait索取才會釋放)。這下好了,父程序直接沒wait就退出了,於是殭屍進城產生後,這個程序id就再也不能被後續使用了。
很簡單,第乙個是signal(可能有的朋友不了解什麼是signal)。linux的訊號機制就提供了其中一種專門用來處理子程序退出問題的,叫sigchld,寫法也非常簡單:
#include
#include
#include
#include
#include
static
void
sig_child
(int signo)
;int
main()
else
if(pid ==0)
printf
("i am father process.i will sleep two seconds\n");
//等待子程序先退出
sleep(2
);//輸出程序資訊
system
("ps -o pid,ppid,state,tty,command");
printf
("father process is exiting.\n");
return0;
}static
void
sig_child
(int signo)
是不是非常簡單?
再給出第二種解決方法,讓父子程序擺脫父子關係,於是子程序的父親變成了init程序,這個程序肯定能幫咱們處理殭屍程序的問題。這確實是一種非常棒的思路,咱們聊聊具體的實現方法:父程序fork乙個子程序,然後子程序裡面再fork乙個孫子程序。這個時候突然子程序建立完成後就退出,那麼,孫子程序就沒有爸爸了(祖安程式設計師)。不能說孫子程序沒有爸爸了,而是說,孫子程序的爸爸變為init程序了。
一起看看實現:
#include
#include
#include
#include
intmain()
//第乙個子程序
else
if(pid ==0)
//第乙個子程序退出
else
if(pid >0)
//第二個子程序
//睡眠3s保證第乙個子程序退出,這樣第二個子程序的父親就是init程序裡
sleep(3
);printf
("i am the second child process.pid: %d\tppid:%d\n"
,getpid()
,getppid()
);exit(0
);}//父程序處理第乙個子程序退出if(
waitpid
(pid,
null,0
)!= pid)
exit(0
);return0;
}
寫時複製就很能理解。各位朋友看看,fork乙個程序可是真的浪費了好多資源啊,啥啥都得複製乙份,太浪費了吧。那能不能咱們搞點棒棒的機制,解決一下這個問題?
寫入時複製(copy-on-write)是乙個被使用在程式設計領域的最佳化策略。其基礎的觀念是,如果有多個呼叫者(callers)同時要求相同資源,他們會共同取得相同的指標指向相同的資源,直到某個呼叫者(caller)嘗試修改資源時,系統才會真正複製乙個副本(private copy)給該呼叫者,以避免被修改的資源被直接察覺到,這過程對其他的呼叫只都是通透的(transparently)。此作法主要的優點是如果呼叫者並沒有修改該資源,就不會有副本(private copy)被建立。
vfork就很省事情,它不會複製乙份新的分頁表,而是依舊指向父程序的分頁表,那麼你倆可不就是共享位址空間了嘛!那不就是你倆共享物理空間了嘛!那肯定不行啊,這樣搞的話豈不是要亂了?
於是vfork有了這樣乙個規則:由vfork創造出來的子程序還會導致父程序掛起,除非子程序exit或者execve才會喚起父程序。這樣一來,不就沒那麼多煩惱了。
vfork命好啊,一定會先於父程序執行。那麼當vfork程序執行完成後,能用return退出麼?
答案肯定是不能!這其實非常好理解。return會釋放掉棧裡面的區域性變數,exit不會。本來父子程序是共享記憶體位址的,對於棧裡面的東西,最好還是vfork剛放進去的就拿出來,換言之,自己玩自己放進去的東西。vfork如果return,那麼棧直接就被糟蹋了。
事出必有因。
咱們先了解一下exec呼叫。
系統呼叫exec是以新的程序去代替原來的程序,但程序的pid保持不變。因此,可以這樣認為,exec系統呼叫並沒有建立新的程序,只是替換了原來程序上下文的內容。原程序的**段,資料段,堆疊段被新的程序所代替。
咱們想想啊,exec一般是在fork程序中執行,本來就要將fork子程序把父程序替換掉,那咱們fork還把位址空間的東西費勁巴拉的拷貝乙份幹嘛呢?
一句話,vfork是給exec用的。
這個咱們就先不深入講解。
clone可以讓你有選擇性的繼承父程序的資源,你可以選擇想vfork一樣和父程序共享乙個虛存空間,從而使創造的是執行緒,你也可以不和父程序共享,你甚至可以選擇創造出來的程序和父程序不再是父子關係,而是兄弟關係。
多執行緒與fork
多執行緒程式裡盡量不使用fork 在多執行緒程式裡,在 自身以外的執行緒存在的狀態 下一使用fork的話,就可能引起各種各樣的問題.比較典型的例子就是,fork出來的子程序可能會死鎖.請不要,在不能把握問題的原委的情況下就在多執行緒程式裡fork子程序,能引起什麼問題呢?那看看例項吧.一執行下面的 ...
12 9 執行緒與fork
當乙個執行緒呼叫函式fork的時候,整個程序位址空間會被拷貝到子程序中,在8.3節中有提到copy on write.子程序是乙個與父程序完全不同的程序,但是如果父程序和子程序都沒有對記憶體內容進行修改,那麼該記憶體頁就可以在父程序與子程序之間進行共享。通過繼承父程序的整個位址空間,子程序也會繼承父...
linux下多執行緒中的fork介紹
目錄 回想一下 當乙個程式只有主線程的時候呼叫fork,此時fowww.cppcns.comrk會建立出的子程序也會只有一條執行緒 那要是把fork放入多執行緒的程式中呢?我們來試驗下 include include include void pthread fun void arg int mai...