Linux下線程的調度-理解


原博地址:有關Linux下線程的調度


由於Linux對線程實現的一些特殊性,所以會給我們理解線程及其相關的一些函數帶來疑惑,這里做個解答:

1、關於sleep

很多書籍上都說sleep這個系統調用會使整個進程sleep,而不單是sleep一個線程。這樣說沒錯,但我們要是在Linux下寫一個多線程 的程序,在一個線程中調用sleep,你會發現其他線程照樣運行,這是怎么回事呢?這就是由於Linux下的線程,其實線程的注冊、銷毀等工作是在 pthread庫里面,而在內核中,線程其實就是一個進程。Linux對線程的實現是通過__clone調用實現的,這個調用會new多個進程出來,只不 過的是, Linux會設置這些進程的共享內存空間、文件描述符等屬性為相同,這樣就實現了線程的定義(共享一個進程的內存空間、線程切換不需要切換上下文環 境……)。所以,很多書籍上會說Linux的線程在核內是輕量級的進程,就是這個道理。因為和普通進程相比,Linux的線程在核內就是一些被設 置了很多屬性的進程,從而實現了線程。

所以,在Linux下,一個線程調用了sleep,反映到核內就是sleep了一個輕量級進程,自然其他的線程(核內的輕量級進程)不受影響,照 樣可以run了。簡言之,之所以sleep一個線程,其他線程仍然可以執行,這是因為在Linux下,線程和進程不是n對1的,而是1對1的。

2、有關線程的調度

有了1的描述,我們就清楚的知道了,其實Linux對線程的調度,策略和進程是基本一致的。所以,很多人問,為什么一個線程中如果有一個循環的 話,其他線程都得不到執行,這就是因為Linux對線程的調度,策略和進程是一樣的,即,如果一個線程處於一個高密度的工作狀態的話,或者該線程的cpu slice沒用完的話,這個線程是不會被調度的。有關這個問題,還可以參看本論壇中“有關線程切換的一個問題”一帖。

其實說白了,明白了第一點的話,很多Linux線程的問題就迎刃而解了。

有關Linux下線程的實現方式,再附上一段“POSIX線程編程指南”(來自IBM Developworks)中的描述,這段描述很專業,很到位:

我們知道,Linux的線程實現是在核外進行的,核內提供的是創建進程的接口do_fork()。內核提供了兩個系統調用__clone()和 fork (),最終都用不同的參數調用do_fork()核內API。當然,要想實現線程,沒有核心對多進程(其實是輕量級進程)共享數據段的支持是不行的,因 此,do_fork()提供了很多參數,包括CLONE_VM(共享內存空間)、CLONE_FS(共享文件系統信息)、CLONE_FILES(共享文 件描述符表)、CLONE_SIGHAND(共享信號句柄表)和CLONE_PID(共享進程ID,僅對核內進程,即0號進程有效)。當使用fork系統 調用時,內核調用do_fork()不使用任何共享屬性,進程擁有獨立的運行環境,而使用pthread_create()來創建線程時,則最終設置了所 有這些屬性來調用__clone(),而這些參數又全部傳給核內的do_fork(),從而創建的”進程”擁有共享的運行環境,只有棧是獨立的,由 __clone()傳入。

Linux線程在核內是以輕量級進程的形式存在的,擁有獨立的進程表項,而所有的創建、同步、刪除等操作都在核外 pthread庫中進行。pthread庫使用一個管理線程(__pthread_manager(),每個進程獨立且唯一)來管理線程的創建和終止,為 線程分配線程ID,發送線程相關的信號(比如Cancel),而主線程(pthread_create())的調用者則通過管道將請求信息傳給管理線程。


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com