下面的表格列展了.NET對(duì)協(xié)調(diào)或同步線程動(dòng)作的可用的工具:
簡(jiǎn)易阻止方法
構(gòu)成 | 目的 |
Sleep | 阻止給定的時(shí)間周期 |
Join | 等待另一個(gè)線程完成 |
鎖系統(tǒng)
構(gòu)成 | 目的 | 跨進(jìn)程? | 速度 |
lock | 確保只有一個(gè)線程訪問(wèn)某個(gè)資源或某段代碼。 | 否 | 快 |
Mutex | 確保只有一個(gè)線程訪問(wèn)某個(gè)資源或某段代碼。可被用于防止一個(gè)程序的多個(gè)實(shí)例同時(shí)運(yùn)行。 | 是 | 中等 |
Semaphore | 確保不超過(guò)指定數(shù)目的線程訪問(wèn)某個(gè)資源或某段代碼。 | 是 | 中等 |
信號(hào)系統(tǒng)
構(gòu)成 | 目的 | 跨進(jìn)程? | 速度 |
EventWaitHandle | 允許線程等待直到它受到了另一個(gè)線程發(fā)出信號(hào)。 | 是 | 中等 |
Wait 和 Pulse* | 允許一個(gè)線程等待直到自定義阻止條件得到滿足。 | 否 | 中等 |
阻止(Blocking)
當(dāng)一個(gè)線程通過(guò)上面所列的方式處于等待或暫停的狀態(tài),被稱(chēng)為被阻止。一旦被阻止,線程立刻放棄它被分配的CPU時(shí)間,將它的ThreadState屬性添加為WaitSleepJoin狀態(tài),直到停止阻止。停止阻止由以下任一條件觸發(fā):
當(dāng)線程通過(guò)(不建議)Suspend 方法暫停,不認(rèn)為是被阻止了。
休眠 和 輪詢(xún)
調(diào)用Thread.Sleep阻止當(dāng)前的線程指定的時(shí)間(或者直到中斷):
static void Main() { Thread.Sleep (0); // 釋放CPU時(shí)間片 Thread.Sleep (1000); // 休眠1000毫秒 Thread.Sleep (TimeSpan.FromHours (1)); // 休眠1小時(shí) Thread.Sleep (Timeout.Infinite); // 休眠直到中斷}確切地說(shuō),Thread.Sleep放棄了占用CPU,請(qǐng)求不再被分配時(shí)間直到超過(guò)某個(gè)給定的時(shí)間。Thread.Sleep(0)放棄CPU的時(shí)間剛剛夠其它在時(shí)間片隊(duì)列里的活動(dòng)線程(如果有的話)被執(zhí)行。
Thread.Sleep在阻止方法中是唯一的暫停捕獲Windows Forms程序的Windows消息的方法,在Windows Forms程序中是一個(gè)很大的問(wèn)題,任何對(duì)主UI線程的阻止都將使程序失去相應(yīng)。因此一般避免這樣使用,無(wú)論信息獲取是否被“技術(shù)地”暫定與否。線程類(lèi)同時(shí)也提供了一個(gè)SpinWait方法,它使用輪詢(xún)CPU而非放棄CPU時(shí)間的方式,保持給定的迭代次數(shù)進(jìn)行“無(wú)用地繁忙”。50迭代停頓大約一微秒,一般取決于CPU的速度和負(fù)載。從技術(shù)上講,SpinWait并不是一個(gè)阻止的方法:一個(gè)處于spin-waiting的線程的ThreadState不是WaitSleepJoin狀態(tài),并且也不會(huì)被其它的線程過(guò)早的中斷(Interrupt)。SpinWait很少被使用,它的作用是等待一個(gè)在極短時(shí)間(可能小于一微秒)內(nèi)可準(zhǔn)備好的可預(yù)期的資源,而不用調(diào)用Sleep方法阻止線程而浪費(fèi)CPU時(shí)間。不過(guò),這種技術(shù)的優(yōu)勢(shì)只有在多處理器計(jì)算機(jī):對(duì)單一處理器的電腦,直到輪詢(xún)的線程結(jié)束了它的時(shí)間片之前,一個(gè)資源沒(méi)有機(jī)會(huì)改變狀態(tài),這有違它的初衷。并且調(diào)用SpinWait經(jīng)常會(huì)花費(fèi)較長(zhǎng)的時(shí)間這本身就浪費(fèi)了CPU時(shí)間。
阻止 vs. 輪詢(xún)
線程可以等待某個(gè)確定的條件來(lái)明確輪詢(xún)使用一個(gè)輪詢(xún)的方式,比如:
while (!PRoceed);
或者:
while (DateTime.Now < nextStartTime);
這是非常浪費(fèi)CPU時(shí)間的:對(duì)于CLR和操作系統(tǒng)而言,線程進(jìn)行了一個(gè)重要的計(jì)算,所以分配了相應(yīng)的資源!在這種狀態(tài)
下的輪詢(xún)線程不算是阻止,不像一個(gè)線程等待一個(gè)EventWaitHandle(一般使用這樣的信號(hào)任務(wù)來(lái)構(gòu)建)。
阻止和輪詢(xún)組合使用可以產(chǎn)生一些變換:
while (!proceed) Thread.Sleep (x); // "輪詢(xún)休眠!"
x越大,CPU效率越高,折中方案是增大潛伏時(shí)間,任何20ms的花費(fèi)是微不足道的,除非循環(huán)中的條件是極其復(fù)雜的。
除了稍有延遲,這種輪詢(xún)和休眠的方式可以結(jié)合的非常好,可能它最大的用處在于程序員可以放棄使用復(fù)雜的信號(hào)結(jié)構(gòu)來(lái)工作了。
使用Join等待一個(gè)線程完成
可以通過(guò)Join方法阻止線程直到另一個(gè)線程結(jié)束:
class ThreadDemo { static void Main() { Thread t = new Thread (delegate() { Console.ReadLine();}); t.Start(); t.Join(); // 等待直到線程完成 Console.WriteLine ("Thread t's ReadLine complete!"); } }Join方法也接收一個(gè)使用毫秒或用TimeSpan類(lèi)的超時(shí)參數(shù),當(dāng)Join超時(shí)是返回false,如果線程已終止,則返回true 。
Join所帶的超時(shí)參數(shù)非常像Sleep方法,實(shí)際上下面兩行代碼幾乎差不多:
Thread.Sleep (1000);
Thread.CurrentThread.Join (1000);
他們的區(qū)別明顯在于單線程的應(yīng)用程序域與COM互操作性:在阻止時(shí),Join保持信息捕獲,Sleep暫停信息捕獲。
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注