clone()函數及其與Linux線程實現的關係

#include<sched.h>
int clone(int (*func)(void*), void *child_stack, int flags, void* fimc_arg ...);
/* pid_t *ptid, struct user_desc* tls, pid_t* ctid*/
還有三個參數在Linux2.6版本中提出,主要是爲了線程的實現。
return process ID of child on success, or -1 on error
  • clone()主要用於linux線程庫的實現。
  • clone創建的新進程幾乎於父進程的翻版。與fork不同的是,克隆生成的進程繼續運行時不會以調用處爲起點,而是去調用以參數func所指定的函數,func又稱爲子函數
  • 進程切換:把運行的進程的CPU寄存器中的數據取出放入內核態的堆棧中,將要運行的進程的數據從內核態堆棧中取出放入CPU寄存器中(硬件上下文),還會把所有一切信息進行切換,內核爲每個進程維護了一個PCB(進程控制塊)用來存儲進程的信息。
  • CPU在對進程進行調度的時候用的是時間片輪轉的方式使多個任務在同一個CPU上執行變成了可能,時間片輪轉算法進程會切換進程,導致切換中的額外開銷(需要切換數據,保存信息加載信息寫入等操作)。
    直接消耗:CPU寄存器需要保存加載,系統調度器的代碼需要執行,TLB實例需要重新加載,CPU的pipeline需要刷掉
    間接消耗:多核cache之間的共享數據,間接消耗對於程序的影響要看線程工作區操作數據的大小。

參數flags

共享文件描述符表: CLONE_FILES

如果指定了CLONE_FILES標誌,父、子進程會共享同一個打開文件描述符表。**意思就是父子進程指向的文件描述符位於同一個虛擬內存中,這樣不管父子進程中誰改變了該文件描述符的性質,對方都會被影響。**如果不設置,那麼就和fork之後的父子進程的文件描述符狀態相同,各自的文件描述符都在各自的虛擬內存中。


共享對信號的處置設置:CLONE_SIGHAND

如果設置了CLONE_SIGHAND,那麼父子進程將共享同一個信號處置表。和共享同一個文件描述符含義相似,就是父子進程中無論誰使用了sigaction或者signal函數改變對信號的處置,則對方都會被影響。如果未設置就和fork調用後的情況相同。


掛起父進程直至子進程退出或調用exec(): CLONE_VFORK
如果設置了CLONE_VFORK,父進程將一直掛起,直至子進程調用exec()或子進程結束爲止。


共享進程的虛擬內存 CLONE_VM

如果設置了CLONE_VM標誌,父子進程會共享同一個虛擬內存頁(如同vfork())。無論哪個進程更新了內存,或是調用了mmap(),munmap(),另一個進程同樣會觀察到這些變化如果未設置CLONE_VM,就如同fork()。

共享同一虛擬內存是線程的關鍵屬性之一,POSIX線程標準對此也有要求。
創建的POISX線程時總是指定了CLONE_VM標誌。


線程組:CLOEN_THREAD

若設置了CLONE_THREAD,則會將子進程置於父進程的線程組中。如果未設置,那麼會將子進程置於新的線程組中。

POSIX標準規定,進程的所有線程共享同一進程ID(既每個線程調用getpid()都應返回相同值),LINUX從2.4版本開始引入了線程組(threads group),以滿足這一需求。

一個線程組內的所有線程擁有同一父進程ID,既線程組與首線程ID相同。**僅當線程組中所有線程都終止後,其父進程纔會收到SIGCHILD信號(或其它終止信號)。**這些行爲符合POSIX線程規範的要求。

從Linux2.6開始,如果設置了CLONE_THREAD,同時也必須設置CLONE_SIGHAND。這也與POSIX線程標準的深入要求相契合。


線程本地存儲: CLONE_SETTLS
如果設置了CLONE_SETTLS,那麼參數tls所指向的user_desc結構對線程所使用的線程本地存儲緩衝區加以描述。


線程庫支持的flags

  • CLONE_PARENT_SETTID 主要目的是因爲ptid的值必須在clone()函數調用完成後才賦值,如果此時創建的線程銷燬,那ptid還沒有賦值,處理器程序就無法正確處理銷燬的線程。設置了該參數後,可以保證在clone()返回之前就給ptid賦值,從而是線程庫避免了這種競爭條件。

CLONE的標誌使用

  • 進程:大體來說,fork()就相當於設置flags爲SIGCHILD的clone調用,而vfork則相當於flags爲(CLONE_VM | CLONE_VFORK | SIGCHILD)。

-NPTL線程實現則使用了clone()函數的所有七個參數來創建線程,flags設置如下:
CLONE_VM | CLONE_FILES | CLONE_FS | CLONE_SIGHAND | CLONE_THREAD | CLONE_SETTLS | CLONE_PARETN_SETTID | CLONE_CHILD_CLEARTID | CLONE_SYSVSEM

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章