<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      練習(xí):自己動(dòng)手實(shí)現(xiàn)一個(gè)輕量級(jí)的信號(hào)量(二)

      話說(shuō)看了Angel Lucifer兄的留言之后,發(fā)現(xiàn)果然Microsoft在June CTP中實(shí)現(xiàn)了SemaphoreSlim,其中不但考慮了與舊的同步對(duì)象在接口上的一致性,還加入了Cancellation的檢查。唉,怪我沒(méi)有跟上形勢(shì)!那么這篇就成班門弄斧了。不過(guò),還應(yīng)該堅(jiān)持把它寫完,善始善終,就當(dāng)為大家整理思路。取笑罷了:-)

       

      上一次說(shuō)到用戶態(tài)與內(nèi)核態(tài)切換帶來(lái)的開銷平均水平是600個(gè)時(shí)鐘周期!因此,如果在大部分時(shí)間內(nèi)。各個(gè)線程對(duì)同步對(duì)象操作時(shí)間非常短暫的情況下,可以先自旋一段時(shí)間,避免直接進(jìn)入內(nèi)核模式,在自旋無(wú)果的情況下再進(jìn)入真正的等待。(這里插一句:可能我說(shuō)的不清楚,造成了大家的誤解,實(shí)際上獲得一個(gè)CriticalSection的操作在用戶態(tài)就可以完成了,但是,一旦鎖已經(jīng)被其他線程持有而需要進(jìn)入等待時(shí),一定會(huì)切換到內(nèi)核模式。這就是為什么說(shuō)使用自旋可以極大限度的避免每次都切換到內(nèi)核模式的原因)。Intel的《多核程序設(shè)計(jì)》一書中就提到,在多核處理器平臺(tái),可以使用

       

      BOOL WINAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount);

       

       

       

       

       

      初始化CriticalSection對(duì)象,使其在進(jìn)入真正等待之前進(jìn)行短暫的自旋而不是直接進(jìn)入等待狀態(tài),也是這個(gè)意思。

       

      好的,首先看看我們?cè)谑裁吹胤叫枰M(jìn)行自旋等待。很顯然就是在Wait剛剛開始,需要獲得鎖的時(shí)候。為了方便,將上一篇中的源代碼摘抄過(guò)來(lái)。

       

       

       1 public bool Wait(int millisecondsTimeout, int waitResNumber)
       2 {
       3     // 參數(shù)檢查工作是必須的
       4     if (millisecondsTimeout < -1)
       5         throw new ArgumentOutOfRangeException("millisecondsTimeout");
       6     if (waitResNumber < 1)
       7         throw new ArgumentOutOfRangeException("waitResNumber");
       8     // 我們?cè)诤竺嬉獌纱翁幚沓瑫r(shí),因此我們需要一個(gè)計(jì)時(shí)器
       9     System.Diagnostics.StopWatch watch = null;
      10     int timeoutNum = millisecondsTimeout;
      11     if (millisecondsTimeout != -1)
      12     {
      13         watch = System.Diagnostics.Stopwatch.StartNew();
      14     }
      15     // 現(xiàn)在我們來(lái)做第(1)步
      16     if (!System.Threading.Monitor.TryEnter(this._globalLock))
      17     {
      18         if (millisecondsTimeout == 0)
      19             return false;
      20         /////////////////////////////////////////////////
      21         // 就是在這里,我們需要先自旋一下,然后再進(jìn)入真正的等待 //
      22         /////////////////////////////////////////////////
      23         if (!System.Threading.Monitor.TryEnter(this._globalLock, millisecondsTimeout))
      24         {
      25             return false;
      26         }
      27     }
      28     // 現(xiàn)在我們已經(jīng)獲得鎖了,我們要增加阻塞的線程數(shù)目,以便將來(lái)有人能夠喚醒我們
      29     ++this._waitingThreadCount;
      30     try
      31     {
      32         // 如果當(dāng)前的資源數(shù)目不夠用的,我們就得等等了
      33         while (this._currentResources - waitResNumber < 0)
      34         {
      35             if (millisecondsTimeout != -1)
      36             {
      37                 // 看看是不是超時(shí)了
      38                 timeoutNum = UpdateTimeout(watch, millisecondsTimeout);
      39                 if (timeoutNum <= 0)
      40                 {
      41                     return false;
      42                 }
      43             }
      44             // 如果沒(méi)有超時(shí)我們就再等一下
      45             if (!System.Threading.Monitor.Wait(this._globalLock, timeoutNum))
      46             {
      47                 return false;
      48             }
      49             // 好的我們被喚醒了,趕快回去檢查檢查有沒(méi)有足夠的資源了
      50         }
      51         // 很好,我們現(xiàn)在有足夠的資源了,
      52         // 并且沒(méi)有什么人能夠再更改資源數(shù)目了,因?yàn)殒i在我們手里!
      53         this._currentResources -= waitResNumber;
      54     }
      55     finally
      56     {
      57         // 很好,我們安全的退出了,減少阻塞的線程數(shù)目并且釋放鎖
      58         --this._waitingThreadCount;
      59         System.Threading.Monitor.Exit(this._globalLock);
      60     }
      61     return true;
      62 }
      63 
      64 

       

       

      直接在上面添加一個(gè)Thread.SpinWait并不很好,因?yàn)槿绻淮蜸pin的時(shí)間較長(zhǎng),就無(wú)謂的浪費(fèi)了時(shí)間,而過(guò)短又不能避免進(jìn)入真正的等待狀態(tài),所以最好是分幾次來(lái)Spin,這樣,在每一次的間歇我們還是可以檢查是否我們已經(jīng)獲得了鎖。自然,要多加上一個(gè)循環(huán):

       

       

       1 public bool Wait(int millisecondsTimeout, int waitResNumber)
       2 {
       3     // 參數(shù)檢查工作是必須的
       4     if (millisecondsTimeout < -1)
       5         throw new ArgumentOutOfRangeException("millisecondsTimeout");
       6     if (waitResNumber < 1)
       7         throw new ArgumentOutOfRangeException("waitResNumber");
       8     // 我們?cè)诤竺嬉獌纱翁幚沓瑫r(shí),因此我們需要一個(gè)計(jì)時(shí)器
       9     System.Diagnostics.Stopwatch watch = null;
      10     int timeoutNum = millisecondsTimeout;
      11     if (millisecondsTimeout != -1)
      12     {
      13         watch = System.Diagnostics.Stopwatch.StartNew();
      14     }
      15     // 現(xiàn)在我們來(lái)做第(1)步
      16     // 這個(gè)值實(shí)際上很有講究,可惜這個(gè)地方我沒(méi)有做很多的測(cè)試
      17     int spinThreshold = 20;
      18     while (true)
      19     {
      20         if (!System.Threading.Monitor.TryEnter(this._globalLock))
      21         {
      22             // 如果不允許超時(shí)設(shè)置則一次獲得失敗就直接退出
      23             if (millisecondsTimeout == 0)
      24                 return false;
      25             // 如果不是無(wú)限等待每次循環(huán)都更新時(shí)間看看有沒(méi)有超時(shí)
      26             else if (millisecondsTimeout != -1)
      27             {
      28                 timeoutNum = UpdateTimeout(watch, millisecondsTimeout);
      29                 if (timeoutNum <= 0)
      30                     return false;
      31             }
      32             if (spinThreshold <= 0)
      33             {
      34                 // 如果自選完畢了就進(jìn)入真正的等待
      35                 if (!System.Threading.Monitor.TryEnter(this._globalLock, millisecondsTimeout))
      36                 {
      37                     return false;
      38                 }
      39                 else
      40                 {
      41                     // 我們最終還是獲得了鎖
      42                     break;
      43                 }
      44             }
      45             else
      46             {
      47                 // 退避自旋
      48                 System.Threading.Thread.SpinWait(21 - spinThreshold);
      49                 --spinThreshold;
      50             }
      51         }
      52         else
      53         {
      54             // 很幸運(yùn),第一次就獲得了鎖!
      55             break;
      56         }
      57     }
      58     // 現(xiàn)在我們已經(jīng)獲得鎖了,我們要增加阻塞的線程數(shù)目,以便將來(lái)有人能夠喚醒我們
      59     ++this._waitingThreadCount;
      60     try
      61     {
      62         // 如果當(dāng)前的資源數(shù)目不夠用的,我們就得等等了
      63         while (this._currentResources - waitResNumber < 0)
      64         {
      65             if (millisecondsTimeout != -1)
      66             {
      67                 // 看看是不是超時(shí)了
      68                 timeoutNum = UpdateTimeout(watch, millisecondsTimeout);
      69                 if (timeoutNum <= 0)
      70                 {
      71                     return false;
      72                 }
      73             }
      74             // 如果沒(méi)有超時(shí)我們就再等一下
      75             if (!System.Threading.Monitor.Wait(this._globalLock, timeoutNum))
      76             {
      77                 return false;
      78             }
      79             // 好的我們被喚醒了,趕快回去檢查檢查有沒(méi)有足夠的資源了
      80         }
      81         // 很好,我們現(xiàn)在有足夠的資源了,
      82         // 并且沒(méi)有什么人能夠再更改資源數(shù)目了,因?yàn)殒i在我們手里!
      83         this._currentResources -= waitResNumber;
      84     }
      85     finally
      86     {
      87         // 很好,我們安全的退出了,減少阻塞的線程數(shù)目并且釋放鎖
      88         --this._waitingThreadCount;
      89         System.Threading.Monitor.Exit(this._globalLock);
      90     }
      91     return true;
      92 }

       

       

      這樣我們就針對(duì)鎖的獲得加入了自旋優(yōu)化,充分避免直接進(jìn)入等待鎖的狀態(tài)。

      剩下的就是以秋風(fēng)掃落葉之勢(shì)編寫余下的代碼了!整體代碼如下:

       

      信號(hào)量的代碼

       

      上面有一處小小的改動(dòng)。就是_waitingThreadCount取消了volatile修飾,因?yàn)槲覀儗?duì)于這個(gè)變量的更新以及獲得均在lock中,已經(jīng)包含了適當(dāng)?shù)腷arrier,因此沒(méi)有必要將其聲明為volatile了。相反的,_currentResourceCount 就需要聲明為 volatile 以保證其有acquire語(yǔ)義。

       

      回頭再看一下微軟實(shí)現(xiàn)的SemaphoreSlim,確實(shí)考慮的很周到,不但考慮了Cancellation(但是很奇怪,一個(gè)Semaphore一旦取消之后就貌似不可能重新恢復(fù)了,只有Dispose之后再用另一個(gè)?。┒铱紤]了與原有的同步對(duì)象的兼容性,方便代碼移植。繼承自WaitHandle,在需要使用內(nèi)核對(duì)象時(shí)Lazy創(chuàng)建并使用內(nèi)核對(duì)象,而在不使用WaitHandle的情況下,使用Monitor對(duì)Semaphore進(jìn)行模擬。在這一點(diǎn)上,確實(shí)應(yīng)當(dāng)學(xué)習(xí)Microsoft,多從用戶(對(duì)于Library,程序員就是用戶?。┑慕嵌瓤紤]。畢竟得用戶者得天下啊。(在東西不是很貴的前提下,哈哈:-D)

      posted @ 2008-07-30 20:44  TW-劉夏  閱讀(2167)  評(píng)論(8)    收藏  舉報(bào)
      主站蜘蛛池模板: av无码小缝喷白浆在线观看| 国产精品亚洲а∨天堂2021| 欧美牲交videossexeso欧美| 国产在线一区二区在线视频| 国产女人喷潮视频免费| 伊人久久大香线蕉av一区二区| 亚洲av产在线精品亚洲第一站| 国产精品一区二区日韩精品| 亚洲精品成人A在线观看| 欧美日韩v| 日韩精品在线观看一二区| 加勒比无码专区中文字幕| 蜜桃无码一区二区三区| 无码h黄肉动漫在线观看| 中文文字幕文字幕亚洲色| 国产乱人偷精品人妻a片| 99久久成人亚洲精品观看| 99久久激情国产精品| 丁香五月婷激情综合第九色| 曰韩亚洲av人人夜夜澡人人爽| 国产成人啪精品视频免费网| 国产一区二区日韩在线| 亚洲欧美中文日韩v在线97| 亚洲V天堂V手机在线| 男女一边摸一边做爽爽| 日本黄页网站免费观看| 日本狂喷奶水在线播放212| 中文字幕日韩精品东京热| 亚洲国产欧美一区二区好看电影| a∨变态另类天堂无码专区| 国产午夜精品理论大片| 国产精品深夜福利免费观看 | 热久久美女精品天天吊色| 安平县| 国产一区二区三区综合视频| 久热这里只有精品12| 国产午夜亚洲精品国产成人| 国产短视频一区二区三区| 国模粉嫩小泬视频在线观看| 亚洲自拍偷拍激情视频| 无码里番纯肉h在线网站|