深入多線程之:用Wait與Pulse模擬一些同步構(gòu)造的應(yīng)用詳解
你可能在上篇文章中《深入多線程之:雙向信號與競賽的用法分析》注意到了這個(gè)模式:兩個(gè)Waiting 循環(huán)都要下面的構(gòu)造:
lock(_locker)
{
while(!_flag) Monitor.Wait(_locker);
_flag = false;
}
在這里_flag被另一線程設(shè)置為true。這是,從作用上講,這里在模仿AutoResetEvent。如果我們將 _flag = false;去掉,那么我們就得到了一個(gè)基本的ManualResetEvent.
讓我們使用Wait和Pulse來為ManualResetEvent完成剩余的代碼吧。
readonly object _locker = new object();
bool _signal;
void WaitOne()
{
lock (_locker)
{
while (!_signal) Monitor.Wait(_locker);
}
}
void Set()
{
lock (_locker) { _signal = true; Monitor.PulseAll(_locker); }
}
void Reset() { lock (_locker) _signal = false; }
在這里使用PulseAll,是因?yàn)榭赡苡泻芏嘧枞木€程。
如果在WaitOne方法中增加_signal=false就可以簡單的模擬AutoResetEvent.例如:
void WaitOne()
{
lock (_locker)
{
while (!_signal) Monitor.Wait(_locker);
_signal = false; //實(shí)現(xiàn)自動關(guān)閉功|能
}
}
然后在Set方法中,將PulseAll修改為Pulse
Lock(_locker) {_signal = true; Monitor.Pulse(_locker);}
如果使用的是int類型的_signal 標(biāo)志,那么我們可以得到一個(gè)最基本的Semaphore.
Waiting Queues and PulseAll
當(dāng)多余一個(gè)線程在同一個(gè)對象上面等待的時(shí)候,一個(gè) “等待隊(duì)列(waiting queue)” 就形成了。
每一次調(diào)用Pulse都會釋放在”等待隊(duì)列”頭部的一個(gè)線程。下面的圖形象的展示了這一點(diǎn):
線程調(diào)用Monitor.Enter 進(jìn)入ReadyQueue. 等待獲取鎖,成功獲取鎖后,如果正常的執(zhí)行,那么之后會調(diào)用Monitor.Exit退出,
否則如果獲取了鎖之后發(fā)現(xiàn)需要等待其他的線程或者是其他阻塞條件,那么調(diào)用Wait方法,就進(jìn)入了等待隊(duì)列,
當(dāng)?shù)却木€程完成并調(diào)用Pulse后,處在WaitingQueue頭部的線程就被 Pulse了,等待CPU調(diào)度 。之后再次進(jìn)入Ready Queue,重新獲取鎖。
Countdown
借助Wait和Pulse,我們可以實(shí)現(xiàn)CountdownEvent的主要功能。例如:
class Countdown
{
object _locker = new object();
int _value; //使用_value來計(jì)數(shù)
public Countdown() { }
public Countdown(int initialCount) { _value = initialCount; }
public void Singnal() { AddCount(-1); } //將計(jì)數(shù)減一
public void AddCount(int amount)
{
lock (_locker)
{
_value += amount; //將計(jì)數(shù)增加或減少
if (_value <= 0) Monitor.PulseAll(_locker);//如果value<=0,說明所有等待的任務(wù)都完成了。
}
}
public void Wait()
{
lock (_locker)
{
//只要計(jì)數(shù) > 0 就等待。
while (_value > 0)
{
Monitor.Wait(_locker);
}
}
}
}
這和我們上次的代碼幾乎一致,只是這次我們的阻塞條件基于一個(gè)整型_value標(biāo)志。
相關(guān)文章
WinForm項(xiàng)目開發(fā)中Excel用法實(shí)例解析
這篇文章主要介紹了WinForm項(xiàng)目開發(fā)中Excel用法,非常實(shí)用,需要的朋友可以參考下2014-08-08C#實(shí)現(xiàn)自由組合本地緩存、分布式緩存和數(shù)據(jù)查詢
這篇文章介紹了C#實(shí)現(xiàn)本地緩存、分布式緩存和數(shù)據(jù)查詢的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07C#實(shí)現(xiàn)用戶自定義控件中嵌入自己的圖標(biāo)
這篇文章主要介紹了C#實(shí)現(xiàn)用戶自定義控件中嵌入自己的圖標(biāo),較為詳細(xì)的分析了C#實(shí)現(xiàn)自定義控件中嵌入圖標(biāo)的具體步驟與相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-03-03