久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

C#線程鎖(下)

 貧窮的小悍馬 2011-09-05
前兩篇簡(jiǎn)單介紹了線程同步lock,,Monitor,同步事件EventWaitHandler,,互斥體Mutex的基本用法,,在此基礎(chǔ)上,我們對(duì)它們用法進(jìn)行比較,,并給出什么時(shí)候需要鎖什么時(shí)候不需要的幾點(diǎn)建議,。最后,介紹幾個(gè)FCL中線程安全的類,,集合類的鎖定方式等,,做為對(duì)線程同步系列的完善和補(bǔ)充。

      1.幾種同步方法的區(qū)別

       lock和Monitor是.NET用一個(gè)特殊結(jié)構(gòu)實(shí)現(xiàn)的,,Monitor對(duì)象是完全托管的,、完全可移植的,并且在操作系統(tǒng)資源要求方面可能更為有效,,同步速度較快,,但不能跨進(jìn)程同步。lock(Monitor.Enter和Monitor.Exit方法的封裝),,主要作用是鎖定臨界區(qū),,使臨界區(qū)代碼只能被獲得鎖的線程執(zhí)行。Monitor.Wait和Monitor.Pulse用于線程同步,,類似信號(hào)操作,,個(gè)人感覺使用比較復(fù)雜,容易造成死鎖,。

       互斥體Mutex和事件對(duì)象EventWaitHandler屬于內(nèi)核對(duì)象,,利用內(nèi)核對(duì)象進(jìn)行線程同步,線程必須要在用戶模式和內(nèi)核模式間切換,,所以一般效率很低,,但利用互斥對(duì)象和事件對(duì)象這樣的內(nèi)核對(duì)象,可以在多個(gè)進(jìn)程中的各個(gè)線程間進(jìn)行同步,。

       互斥體Mutex類似于一個(gè)接力棒,,拿到接力棒的線程才可以開始跑,當(dāng)然接力棒一次只屬于一個(gè)線程(Thread Affinity),如果這個(gè)線程不釋放接力棒(Mutex.ReleaseMutex),,那么沒辦法,,其他所有需要接力棒運(yùn)行的線程都知道能等著看熱鬧。

       EventWaitHandle 類允許線程通過發(fā)信號(hào)互相通信,。通常,,一個(gè)或多個(gè)線程在 EventWaitHandle 上阻止,直到一個(gè)未阻止的線程調(diào)用 Set 方法,,以釋放一個(gè)或多個(gè)被阻止的線程,。

      2.什么時(shí)候需要鎖定

       首先要理解鎖定是解決競(jìng)爭(zhēng)條件的,也就是多個(gè)線程同時(shí)訪問某個(gè)資源,,造成意想不到的結(jié)果,。比如,最簡(jiǎn)單的情況是,,一個(gè)計(jì)數(shù)器,,兩個(gè)線程 同時(shí)加一,后果就是損失了一個(gè)計(jì)數(shù),,但相當(dāng)頻繁的鎖定又可能帶來性能上的消耗,,還有最可怕的情況死鎖。那么什么情況下我們需要使用鎖,,什么情況下不需要 呢,?

       1)只有共享資源才需要鎖定
       只有可以被多線程訪問的共享資源才需要考慮鎖定,比如靜態(tài)變量,,再比如某些緩存中的值,,而屬于線程內(nèi)部的變量不需要鎖定。

       2)多使用lock,少用Mutex
      如果你一定要使用鎖定,,請(qǐng)盡量不要使用內(nèi)核模塊的鎖定機(jī)制,,比如.NET的Mutex,Semaphore,,AutoResetEvent和 ManuResetEvent,,使用這樣的機(jī)制涉及到了系統(tǒng)在用戶模式和內(nèi)核模式間的切換,性能差很多,,但是他們的優(yōu)點(diǎn)是可以跨進(jìn)程同步線程,,所以應(yīng)該清 楚的了解到他們的不同和適用范圍。

      3)了解你的程序是怎么運(yùn)行的
      實(shí)際上在web開發(fā)中大多數(shù)邏輯都是在單個(gè)線程中展開的,,一個(gè)請(qǐng)求都會(huì)在一個(gè)單獨(dú)的線程中處理,,其中的大部分變量都是屬于這個(gè)線程的,根本沒有必要考慮鎖定,,當(dāng)然對(duì)于ASP.NET中的Application對(duì)象中的數(shù)據(jù),,我們就要考慮加鎖了,。

      4)把鎖定交給數(shù)據(jù)庫(kù)
      數(shù) 據(jù)庫(kù)除了存儲(chǔ)數(shù)據(jù)之外,還有一個(gè)重要的用途就是同步,,數(shù)據(jù)庫(kù)本身用了一套復(fù)雜的機(jī)制來保證數(shù)據(jù)的可靠和一致性,,這就為我們節(jié)省了很多的精力。保證了數(shù)據(jù)源 頭上的同步,,我們多數(shù)的精力就可以集中在緩存等其他一些資源的同步訪問上了,。通常,只有涉及到多個(gè)線程修改數(shù)據(jù)庫(kù)中同一條記錄時(shí),,我們才考慮加鎖。

      5)業(yè)務(wù)邏輯對(duì)事務(wù)和線程安全的要求
      這 條是最根本的東西,,開發(fā)完全線程安全的程序是件很費(fèi)時(shí)費(fèi)力的事情,,在電子商務(wù)等涉及金融系統(tǒng)的案例中,許多邏輯都必須嚴(yán)格的線程安全,,所以我們不得不犧牲 一些性能,,和很多的開發(fā)時(shí)間來做這方面的工作。而一般的應(yīng)用中,,許多情況下雖然程序有競(jìng)爭(zhēng)的危險(xiǎn),,我們還是可以不使用鎖定,比如有的時(shí)候計(jì)數(shù)器少一多一,, 對(duì)結(jié)果無傷大雅的情況下,,我們就可以不用去管它。

      3.InterLocked類

      Interlocked 類提供了同步對(duì)多個(gè)線程共享的變量的訪問的方法,。如果該變量位于共享內(nèi)存中,,則不同進(jìn)程的線程就可以使用該機(jī)制?;ユi操作是原子的,,即整個(gè)操作是不能由相 同變量上的另一個(gè)互鎖操作所中斷的單元。這在搶先多線程操作系統(tǒng)中是很重要的,,在這樣的操作系統(tǒng)中,,線程可以在從某個(gè)內(nèi)存地址加載值之后但是在有機(jī)會(huì)更改 和存儲(chǔ)該值之前被掛起。

      我們來看一個(gè)InterLock.Increment()的例子,,該方法以原子的形式遞增指定變量并存儲(chǔ)結(jié)果,,示例如下:

Increment()方法累加的示例
    class InterLockedTest
     {
        
public static Int64 i = 0;

        
public static void Add()
         {
            
for (int i = 0; i < 100000000; i++)
             {
                 Interlocked.Increment(
ref InterLockedTest.i);
                
//InterLockedTest.i = InterLockedTest.i + 1;
             }
         }


        
public static void Main(string[] args)
         {
             Thread t1
= new Thread(new ThreadStart(InterLockedTest.Add));
             Thread t2
= new Thread(new ThreadStart(InterLockedTest.Add));

             t1.Start();
             t2.Start();

             t1.Join();
             t2.Join();

             Console.WriteLine(InterLockedTest.i.ToString());
             Console.Read();
         }
     }

      輸出結(jié)果200000000,,如果InterLockedTest.Add()方法中用注釋掉的語句代替Interlocked.Increment()方法,,結(jié)果將不可預(yù)知,每次執(zhí)行結(jié)果不同,。InterLockedTest.Add()方法保證了加1操作的原子性,,功能上相當(dāng)于自動(dòng)給加操作使用了lock鎖,。同時(shí)我們也注意到InterLockedTest.Add()用時(shí)比直接用+號(hào)加1要耗時(shí)的多,,所以說加鎖資源損耗還是很明顯的。

      另外InterLockedTest類還有幾個(gè)常用方法,,具體用法可以參考MSDN上的介紹,。

      4.集合類的同步

      .NET在一些集合類,比如Queue,、ArrayList,、HashTable和Stack,已經(jīng)提供了一個(gè)供lock使用的對(duì)象SyncRoot,。用Reflector查看了SyncRoot屬性(Stack.SynchRoot略有不同)的源碼如下:

SyncRoot屬性源碼
public virtual object SyncRoot
{
    
get
     {
        
if (this._syncRoot == null)
         {
            
//如果_syncRoot和null相等,,將new object賦值給_syncRoot
            
//Interlocked.CompareExchange方法保證多個(gè)線程在使用syncRoot時(shí)是線程安全的
             Interlocked.CompareExchange(ref this._syncRoot, new object(), null);
         }
        
return this._syncRoot;
     }
}

      這里要特別注意的是MSDN提到:從頭到尾對(duì)一個(gè)集合進(jìn)行枚舉本質(zhì)上并不是一個(gè)線程安全的過程。即使一個(gè)集合已進(jìn)行同步,,其他線程仍可以修改該集合,,這將導(dǎo)致枚舉數(shù)引發(fā)異常。若要在枚舉過程中保證線程安全,,可以在整個(gè)枚舉過程中鎖定集合,,或者捕捉由于其他線程進(jìn)行的更改而引發(fā)的異常。應(yīng)該使用下面的代碼:

Queue使用lock示例
     Queue q = new Queue();
    
lock (q.SyncRoot)
     {
        
foreach (object item in q)
         {
            
//do something
         }
     }

      還有一點(diǎn)需要說明的是,,集合類提供了一個(gè)是和同步相關(guān)的方法Synchronized,,該 方法返回一個(gè)對(duì)應(yīng)的集合類的wrapper類,該類是線程安全的,,因?yàn)樗拇蟛糠址椒ǘ加胠ock關(guān)鍵字進(jìn)行了同步處理,。如HashTable的 Synchronized返回一個(gè)新的線程安全的HashTable實(shí)例,代碼如下:

Synchronized的使用和理解
    //在多線程環(huán)境中只要我們用下面的方式實(shí)例化HashTable就可以了
     Hashtable ht = Hashtable.Synchronized(new Hashtable());

    
//以下代碼是.NET Framework Class Library實(shí)現(xiàn),,增加對(duì)Synchronized的認(rèn)識(shí)
     [HostProtection(SecurityAction.LinkDemand, Synchronization=true)]
    
public static Hashtable Synchronized(Hashtable table)
     {
        
if (table == null)
         {
            
throw new ArgumentNullException("table");
         }
        
return new SyncHashtable(table);
     }


    
//SyncHashtable的幾個(gè)常用方法,,我們可以看到內(nèi)部實(shí)現(xiàn)都加了lock關(guān)鍵字保證線程安全
    public override void Add(object key, object value)
     {
        
lock (this._table.SyncRoot)
         {
            
this._table.Add(key, value);
         }
     }

    
public override void Clear()
     {
        
lock (this._table.SyncRoot)
         {
            
this._table.Clear();
         }
     }

    
public override void Remove(object key)
     {
        
lock (this._table.SyncRoot)
         {
            
this._table.Remove(key);
         }
     }

      線程同步是一個(gè)非常復(fù)雜的話題,這里只是根據(jù)公司的一個(gè)項(xiàng)目把相關(guān)的知識(shí)整理出來,,作為工作的一種總結(jié),。這些同步方法的使用場(chǎng)景是怎樣的?究竟有哪些細(xì)微的差別,?還有待于進(jìn)一步的學(xué)習(xí)和實(shí)踐,。


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多