天天看點

.NET簡談元件程式設計之(上下文與同步域)

我們繼續學習.NET多線程技術,這篇文章的内容可能有點複雜。在打破常理之後,換一種新的思考模型最為頭疼。這篇文章裡面會涉及到一些不太常見的概念,比如:上下文、同步域等等。我也是最近才接觸這些關于元件程式設計方面的高深技術,大家一起學習,再大的困難也是有時間限制的,隻要我們堅持。

這篇文章的重點是學習關于線程的同步、互斥的機制。在多線程的應用程式中,最少會有一個主線程在運作着,如果我們想提高應用程式的吞吐量就必須借助多線程的原理來實作。[王清培版權所有,轉載請給出署名]

.NET上下文(ContextBoundObject對象)

什麼叫上下文,千萬别和ASP.NET中的上下文搞混了,這個上下文是個形容詞,在不同的場合有不同的意思。在ASP.NET中的上下文是指Context對象,這個對象基本上包容了HTTP協定的整個生命周期的資訊,可以擷取到用戶端浏覽器的一些基本資訊,也可以擷取到關于HTTP協定的一些資訊,等等。

這裡所講的上下文是.NET程式執行的最小邏輯範圍,ASP.NET上下文是站在B/S程式設計模型角度去看待的,而這裡的上下文是站在.NET底層運作角度看來的,後者是代碼的上下文,前者是整個生命周期的上下文。

在沒有接觸ContextBoundObject之前我一直以為.NET程式執行的最小邏輯範圍是應用程式域(AppDomain),知道了之後才知道另有隐情,上下文是用來确定對象的邏輯歸屬,在多線程(Thread)、事物處理(Transaction)、企業服務(Enterprise)等方面都需要用上下文來對對象進行規劃。下面您将看到怎麼用上下文來進行線程的同步的。

圖1:

<a target="_blank" href="http://blog.51cto.com/attachment/201108/104337784.png"></a>

.NET同步域(Synchronization特性)

同步域的概念是來源于多線程的場合,在我們進行多線程操作的時候,讓很多個線程去同時通路一個記憶體對象的時候,是必須用鎖來保證隻有一個線程進入對象操作的,那麼同步域的概念就是同步的是一個區域,而不是單單的一個對象。

線程是代碼的執行路徑,隻要在這條執行路徑上都屬于線程的範圍,那麼怎麼在執行的路徑中分離出另外一個同步區域。[王清培版權所有,轉載請給出署名]

臨界資源是系統中對同一時間隻能由一個線程進行通路的描述。我們假設自己就是一個線程,我們要去家裡拿點東西,那麼門就是線程的同步鎖,當我們進去的時候就把門從裡面反鎖,出去的時候就把門打開,以友善自己的家人進來。這個房子就是臨界資源。可能這樣的描述不太靠譜,哪有這樣的家啊!

圖2:

<a target="_blank" href="http://blog.51cto.com/attachment/201108/123650624.png"></a>

利用上下文和同步域進行線程的同步

下面我們将結合上下文和同步域的原理進行線程的同步。請看一段代碼:

using System;  

using System.Collections.Generic;  

using System.Text;  

using System.Threading;  

using System.Runtime.Remoting;  

using System.Runtime.Remoting.Contexts;  

namespace ConsoleApplication1.多線程和并發管理  

{  

    //如果不加上下文,那麼就是以對象為線程鎖定區域,如果加上下文,那麼就是已邏輯上下文為鎖定區域  

    [Synchronization(SynchronizationAttribute.REQUIRED, true)]//重新進入同步域  

    public class MyClass : ContextBoundObject  

    {  

        public void DoWork()  

        {  

            int i = 0;  

            while (true)  

            {  

                Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "|" + i++);  

                if (i == 10)  

                {  

                    Console.WriteLine("---------------------------------------------");  

                    Console.Read();  

                    break;  

                }  

            }  

        }  

    }  

}  

在這段代碼裡面,我給Myclass類加上了Synchronization特性,并且繼承自上下文對象ContextBoundObject。兩者必須集合使用,同步域隻有在上下文中才有效。

【MSDN:将 SynchronizationAttribute 應用到一個上下文綁定對象會導緻建立等待句柄和自動重置事件,這些内容不一定會被作為垃圾來回收。是以,不要在很短的時間内建立大量用 SynchronizationAttribute 标記的上下文綁定對象。】

圖3:

圖4:

<a target="_blank" href="http://blog.51cto.com/attachment/201108/132141351.png"></a>

我們來看調用代碼:

Thread currentthread = Thread.CurrentThread;  

            Console.WriteLine(currentthread.Name + currentthread.ManagedThreadId);  

            MyClass myclass = new MyClass();  

            Thread thread = new Thread(new ThreadStart(myclass.DoWork));  

            Thread thread2 = new Thread(new ThreadStart(myclass.DoWork));  

            thread2.Start();  

            thread.Start();  

            thread2.Join();  

            thread.Join();  

            Console.Read(); 

圖5:

<a target="_blank" href="http://blog.51cto.com/attachment/201108/130458733.png"></a>

我為了友善截圖是以把循環的數字設的比較小,如果你想測試一下,可以把數字設的大一點。[王清培版權所有,轉載請給出署名]

在SynchronizationAttribute對象裡面有幾個枚舉值,是用來确定是否共享一個同步域的,有興趣的可以自己嘗試,我就不在這裡多講了。

總結:同步域和上下文對象是線程自動同步的好方法,但是他鎖定的目标太大,難免導緻系統的吞吐量下降,是以下面幾篇文章我們将會學習怎麼使用手動同步來實作更靈活的同步(Monitor、WaitHandler等),從很小的粒度進行鎖定。

 本文轉自 王清培 51CTO部落格,原文連結:http://blog.51cto.com/wangqingpei557/652057,如需轉載請自行聯系原作者

繼續閱讀