| 導購 | 订阅 | 在线投稿
分享
 
 
 

進程與線程雜談(一)

來源:互聯網  2004-11-11 09:31:11  評論

進程與線程雜談(一)

--轉載

我了解不多,只能說說80x86上的Windows環境,其他如Alpha,Mac或者Linux,

我就一竅不通了,見笑見笑……

現代操作系統都是多任務的操作系統,在這裏要澄清一個概念,Windows 3.x時代也

有所謂的多任務,但是,那並不是現代意義的多任務--"搶占式多任務"。Windows 3.x的

多任務是非搶占式的,即,一個應用程序,甚至系統,要等現在正在運行的程序主動放棄

CPU(程序員把這個禮貌的行爲寫到程序中),才能獲得執行時間片。可以看出,在這種環

境中,操作系統的主動性是很小的,只要某個已經獲得CPU的程序不主動放棄CPU,操作

系統就得不到時間運行,亦無法實行其管理調度功能。如果一個應用程序因崩潰而挂起,

將導致整個系統挂起。

而搶占式的多任務是指,將CPU時間片分配最需要它的應用程序,即便一個應用程序永

遠不打算放棄CPU,操作系統也能保證隨時"搶占"CPU時間,然後對當前所有的任務進行

合理的調度。

要實現多任務,首先要有CPU的支持,80x86 (Alpha?我不懂,別問我……) 支持

多任務,通過一個TSS--任務描述符,80x86能夠描述一個任務。詳細我就不說了,和本

文關系不大,只要說明搶占式多任務不是操作系統在單幹就行了。

作爲操作系統,要能夠利用CPU提供的功能才能實現多任務,Windows做到了這點(當

然,Linux也做到了,只是我不懂……)。系統有一個核心調度程序,負責爲每一個任務分配

CPU時間,允許其執行指定的一段時間,當這段時間用完後,控制權會重新交回到操作系統,

操作系統可在此時重新分配CPU時間。至于CPU時間是如何分配的,就又不是本文的範圍了。

Microsoft給出的文檔是說"系統保證CPU時間的分配是公平的",僅此而已……。

在Windows中,一個任務就是一個線程,以前曾經說過,線程不能沒有存儲而存在,

而其所依賴存在的存儲對象就是進程。而一個進程--以前也說過了--對應一個映象(可執行

文件)。也就是說,在一個可執行文件運行時,可以有多個線程。

好了,基本的概念大概說明了,來討論一下它們的用途。要這些多出來(除了原始線程

外)的線程有什麽用?MSDN給出的答案是"等"。但我個人認爲稍微籠統了一點(偏激一點?

)。不過,至少,有一點是肯定的--絕不要使多個線程同時進行繁重的操作--除非你是建立

了CPU數目個線程(32路對等處理器系統?)。無論如何,實際工作的還是CPU,在這種情

況下,CPU不僅不會少執行指令,還要執行很多的排班程序指令以及任務的切換指令--反而

降低效率。

在需要等待的地方,多線程確實能夠發揮很高的效能。(注意,並不一定是最高,以後

將說到經常是更好的實現方法,這裏只是說明線程的用法)舉一個例子:一個網絡程序向遠

程主機發送了一個請求,正在等待回應,而在此期間,它還希望能夠與用戶進行交互。一種

實現方法是:程序繼續與用戶交互,在交互的間歇檢查一下回應是否到達。而更好的方法是

建立一個新的線程(稱爲工作線程)來等待回應,原始線程繼續照常與用戶交互。如果您已

經感覺到後一種方法確實比前一種方法好很多,那麽,您可以不讀下一段,不用聽我羅嗦了。

後一種方法比前一種方法好在後者執行的指令更少,因而效率更高。如果您對Windows

編程熟悉:在實現前者時,必須保證能夠及時檢測到回應到達,因而就不能使用GetMessage()

而要使用PeekMessage()。如果使用GetMessage(),而恰巧在很長的一段時間內都沒

有消息到達,原始線程就不會從GetMessage()返回,也就不能檢測回應是否到達。使用

PeekMessage(),可以令其在沒有消息時也立即返回,因而可以檢測回應是否到達。網絡

部分的情況也一樣--程序不能等回應一直等下去否則就無法與用戶交互。無論如何,在即沒

有消息、也沒有回應到達的情況下,原始線程沒有有效的進入等待狀態,而是不停地"空轉",

檢測二者中是否有到達的,這對系統資源顯然是極大的浪費。而對于後者,原始線程通過

GetMessage()有效的進入了等待,工作線程也可以通過類似的方法進入等待,例如使用

Socket的select()。

但是,新的問題又出現了,工作線程發現回應已經到達了,它可能要通知原始線程才行

--它與原始線程是並發執行的。這就涉及到線程簡通信了,有一種最簡單的方法:Windows

消息。工作線程通過向原始線程的窗口發送一個消息,然後終止;當原始線程的消息循環發

現這個消息時,就知道回應已經到達了。線程間通信的方法還有很多,將在以後專門介紹。

最後要說明的是--很重要的一點:多線程經常不是程序員主動來使用的,而是在依賴操

作系統時,已然是多線程了。即使用,也很有節制,濫用線程將適得其反。究竟什麽地方應

該使用多線程,並沒有什麽規則,將多線程用在該用的地方而已,當然不會刻意的使用它。

當綜合各種條件和各種可能的方案後,如發現多線程是最好的,就是使用多線程的最佳時機。

我是否說的是廢話?呵呵,其實就像這篇文章一樣,我也很頭疼,線程是在遇到實際需要時

才想起用的,硬要設計一種情況來使用實在不易。有備無患。多線程不是殺手锏,但是掌握

它是向較高級編程邁進的必經之路。

進程與線程雜談(一) --轉載 我了解不多,只能說說80x86上的Windows環境,其他如Alpha,Mac或者Linux, 我就一竅不通了,見笑見笑……   現代操作系統都是多任務的操作系統,在這裏要澄清一個概念,Windows 3.x時代也 有所謂的多任務,但是,那並不是現代意義的多任務--"搶占式多任務"。Windows 3.x的 多任務是非搶占式的,即,一個應用程序,甚至系統,要等現在正在運行的程序主動放棄 CPU(程序員把這個禮貌的行爲寫到程序中),才能獲得執行時間片。可以看出,在這種環 境中,操作系統的主動性是很小的,只要某個已經獲得CPU的程序不主動放棄CPU,操作 系統就得不到時間運行,亦無法實行其管理調度功能。如果一個應用程序因崩潰而挂起, 將導致整個系統挂起。   而搶占式的多任務是指,將CPU時間片分配最需要它的應用程序,即便一個應用程序永 遠不打算放棄CPU,操作系統也能保證隨時"搶占"CPU時間,然後對當前所有的任務進行 合理的調度。   要實現多任務,首先要有CPU的支持,80x86 (Alpha?我不懂,別問我……) 支持 多任務,通過一個TSS--任務描述符,80x86能夠描述一個任務。詳細我就不說了,和本 文關系不大,只要說明搶占式多任務不是操作系統在單幹就行了。   作爲操作系統,要能夠利用CPU提供的功能才能實現多任務,Windows做到了這點(當 然,Linux也做到了,只是我不懂……)。系統有一個核心調度程序,負責爲每一個任務分配 CPU時間,允許其執行指定的一段時間,當這段時間用完後,控制權會重新交回到操作系統, 操作系統可在此時重新分配CPU時間。至于CPU時間是如何分配的,就又不是本文的範圍了。 Microsoft給出的文檔是說"系統保證CPU時間的分配是公平的",僅此而已……。   在Windows中,一個任務就是一個線程,以前曾經說過,線程不能沒有存儲而存在, 而其所依賴存在的存儲對象就是進程。而一個進程--以前也說過了--對應一個映象(可執行 文件)。也就是說,在一個可執行文件運行時,可以有多個線程。   好了,基本的概念大概說明了,來討論一下它們的用途。要這些多出來(除了原始線程 外)的線程有什麽用?MSDN給出的答案是"等"。但我個人認爲稍微籠統了一點(偏激一點? )。不過,至少,有一點是肯定的--絕不要使多個線程同時進行繁重的操作--除非你是建立 了CPU數目個線程(32路對等處理器系統?)。無論如何,實際工作的還是CPU,在這種情 況下,CPU不僅不會少執行指令,還要執行很多的排班程序指令以及任務的切換指令--反而 降低效率。   在需要等待的地方,多線程確實能夠發揮很高的效能。(注意,並不一定是最高,以後 將說到經常是更好的實現方法,這裏只是說明線程的用法)舉一個例子:一個網絡程序向遠 程主機發送了一個請求,正在等待回應,而在此期間,它還希望能夠與用戶進行交互。一種 實現方法是:程序繼續與用戶交互,在交互的間歇檢查一下回應是否到達。而更好的方法是 建立一個新的線程(稱爲工作線程)來等待回應,原始線程繼續照常與用戶交互。如果您已 經感覺到後一種方法確實比前一種方法好很多,那麽,您可以不讀下一段,不用聽我羅嗦了。   後一種方法比前一種方法好在後者執行的指令更少,因而效率更高。如果您對Windows 編程熟悉:在實現前者時,必須保證能夠及時檢測到回應到達,因而就不能使用GetMessage() 而要使用PeekMessage()。如果使用GetMessage(),而恰巧在很長的一段時間內都沒 有消息到達,原始線程就不會從GetMessage()返回,也就不能檢測回應是否到達。使用 PeekMessage(),可以令其在沒有消息時也立即返回,因而可以檢測回應是否到達。網絡 部分的情況也一樣--程序不能等回應一直等下去否則就無法與用戶交互。無論如何,在即沒 有消息、也沒有回應到達的情況下,原始線程沒有有效的進入等待狀態,而是不停地"空轉", 檢測二者中是否有到達的,這對系統資源顯然是極大的浪費。而對于後者,原始線程通過 GetMessage()有效的進入了等待,工作線程也可以通過類似的方法進入等待,例如使用 Socket的select()。   但是,新的問題又出現了,工作線程發現回應已經到達了,它可能要通知原始線程才行 --它與原始線程是並發執行的。這就涉及到線程簡通信了,有一種最簡單的方法:Windows 消息。工作線程通過向原始線程的窗口發送一個消息,然後終止;當原始線程的消息循環發 現這個消息時,就知道回應已經到達了。線程間通信的方法還有很多,將在以後專門介紹。   最後要說明的是--很重要的一點:多線程經常不是程序員主動來使用的,而是在依賴操 作系統時,已然是多線程了。即使用,也很有節制,濫用線程將適得其反。究竟什麽地方應 該使用多線程,並沒有什麽規則,將多線程用在該用的地方而已,當然不會刻意的使用它。 當綜合各種條件和各種可能的方案後,如發現多線程是最好的,就是使用多線程的最佳時機。 我是否說的是廢話?呵呵,其實就像這篇文章一樣,我也很頭疼,線程是在遇到實際需要時 才想起用的,硬要設計一種情況來使用實在不易。有備無患。多線程不是殺手锏,但是掌握 它是向較高級編程邁進的必經之路。
󰈣󰈤
王朝萬家燈火計劃
期待原創作者加盟
 
 
 
>>返回首頁<<
 
 
 
 
 熱帖排行
 
 
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有