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