Linux 進程,線程,線程池

在linux內核,線程與進程的區別很小,或者說內核並無真正所謂單獨的線程的概念,進程的建立函數是fork,而線程的建立是經過clone實現的。linux

而clone與fork都是調用do_fork(),差別以下:api

 1 SYSCALL_DEFINE0(fork)
 2 {
 3     return do_fork(SIGCHLD, 0, 0, NULL, NULL);
 4 }
 5 
 6 SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
 7          int __user *, parent_tidptr,
 8          int __user *, child_tidptr,
 9          int, tls_val)
10 {
11     return do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr);
12 }

實際上就是內核開放大部分參數和do_fork接口來建立線程,看clone的官方解釋:異步

The main use of clone() is to implement threads: multiple threads of control in a program that run concurrently in a shared memory space.

因此接下來參考glibc 2.25版本的pthread_create來看看進程和線程的具體實現差別在哪裏:函數

1 const int clone_flags = (CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SYSVSEM
2                | CLONE_SIGHAND | CLONE_THREAD
3                | CLONE_SETTLS | CLONE_PARENT_SETTID
4                | CLONE_CHILD_CLEARTID
5                | 0);

顯而易見clone_flags的差異很是大.工具

下面再來經過這些flags的做用來區分進程和線程的特性,細數以前先看看do_fork的實現,發現有意思的是,ptrace和perf這2個調試工具也是進程建立的時候初始化的.spa

一、CLONE_VM線程

     首先線程不能脫離父進程獨立存在,因此它須要共享父進程的虛擬內存空間調試

二、CLONE_FS | CLONE_FILEScode

    線程作爲父進程一個CPU執行單元,它能夠直接使用父進程的文件系統信息(包括文件系統根目錄,當前工做目錄,和文件訪問權限)而不須要本身獨立建立和持有這些資源和父進程打開的文件描述符blog

三、CLONE_SIGHAND | CLONE_THREAD

    線程還接着共享父進程的異步信號處理函數,即父進程能收到的異步信號,它也能收到並處理,不過線程能夠自行經過sigprocmask來屏蔽或不屏蔽某些異步信號操做,而不影響其餘線程。

四、CLONE_SYSVSEM

    線程共享父進程的System V semaphore。

五、CLONE_SETTLS

    線程支持TLS (Thread Local Storage)。TLS使得變量每個線程有一份獨立實體,各個線程的值互不干擾

六、CLONE_PARENT_SETTID

    父進程和線程會將線程ID保存在內核任務結構體的ptid成員。

七、CLONE_CHILD_CLEARTID

    清除內核任務結構體的ctid成員上存儲的線程ID。

八、CLONE_THREAD

    將線程放入到父進程的線程組(thread group)裏,這樣線程在用戶態就看不到本身進程ID了,只能看到父進程的進程ID,而且線程共享父進程的異步信號。

 

子進程則會複製父進程的不少進程信息,複製與共享的區別仍是很大的,複製須要從新申請內核資源,因此開銷比線程大不少。

一、建立進程的時候沒有指定 CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,因此這些它須要複製進程的,因此父進程這些信息也被子進程繼承過去了,可是已經獨立存在在子進程裏了,之後就沒有關係了。

二、子進程還複製父進程的信號處理函數和信號;

三、線程和子進程都會繼承(複製)父進程的普通優先級,父進程的棧,CPU狀態會被設置爲RUNNING。

 

總結一下:

一、進程,線程的建立還有不少細節,我這裏沒有徹底列舉出來,只列舉了我以爲比較重要的部分。

二、線程,進程的最大區別就是,啃老仍是不啃老,經過上面來看,線程就是個啃老的貨,而進程是個依靠父母獨立成長的好孩子,然並卵,事實證實,不論是現實世界仍是計算機這個虛擬世界,越獨立就越佔用資源!

四、因此,多用線程能夠下降系統資源的消耗。

 

上面講到要多用線程,下面就輪到線程池要出場了,可是這個世界老是有不少熊孩子,就喜歡不停給他老子搞事情,嚴重到。。。咳咳,咱們仍是嚴肅的描述吧:

嚴重到不停的建立線程,銷燬線程,這就增長了內核的開銷了,更有甚之,有的線程函數無比簡短,可能線程剛建立完就要銷燬了。。。

因此避免出現這樣的狀況,不少場合須要用到進程池。

 

 

關於pthread能夠參考以下文章:

http://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part1/

https://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part2/

https://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part3/

https://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part4/

https://www.ibm.com/developerworks/cn/linux/thread/posix_threadapi/part5/

相關文章
相關標籤/搜索