亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C#多線程編程中的鎖系統(tǒng)基本用法

 更新時間:2015年04月10日 09:32:36   投稿:junjie  
這篇文章主要介紹了C#多線程編程中的鎖系統(tǒng)基本用法,本文講解了lock、Monitor、mutex、Semaphore等內(nèi)容,需要的朋友可以參考下

平常在多線程開發(fā)中,總避免不了線程同步。本篇就對net多線程中的鎖系統(tǒng)做個簡單描述。

目錄
一:lock、Monitor
     1:基礎(chǔ)。
     2: 作用域。
     3:字符串鎖。
     4:monitor使用
二:mutex
三:Semaphore
四:總結(jié)

一:lock、Monitor

1:基礎(chǔ)

Lock是Monitor語法糖簡化寫法。Lock在IL會生成Monitor。

復(fù)制代碼 代碼如下:

//======Example 1=====
            string obj = "helloworld";
            lock (obj)
            {
                Console.WriteLine(obj);
            }
            //lock  IL會編譯成如下寫法
            bool isGetLock = false;
            Monitor.Enter(obj, ref isGetLock);
            try
            {
                Console.WriteLine(obj);
            }
            finally
            {
                if (isGetLock)
                {
                    Monitor.Exit(obj);
                }
            }

isGetLock參數(shù)是Framework  4.0后新加的。 為了使程序在所有情況下都能夠確定,是否有必要釋放鎖。例: Monitor.Enter拿不到鎖

Monitor.Enter 是可以鎖值類型的。鎖時會裝箱成新對象,所以無法做到線程同步。

2:作用域

     一:Lock是只能在進程內(nèi)鎖,不能跨進程。走的是混合構(gòu)造,先自旋再轉(zhuǎn)成內(nèi)核構(gòu)造。

     二:關(guān)于對type類型的鎖。如下:

復(fù)制代碼 代碼如下:

//======Example 2=====
            new Thread(new ThreadStart(() => {
                lock (typeof(int))
                {
                    Thread.Sleep(10000);
                    Console.WriteLine("Thread1釋放");
                }
            })).Start();
            Thread.Sleep(1000);
            lock(typeof(int))
            {
                Console.WriteLine("Thread2釋放");
            }

運行結(jié)果如下:

我們在來看個例子。

復(fù)制代碼 代碼如下:

//======Example 3=====
            Console.WriteLine(DateTime.Now);
            AppDomain appDomain1 = AppDomain.CreateDomain("AppDomain1");
            LockTest Worker1 = (LockTest)appDomain1.CreateInstanceAndUnwrap(
             Assembly.GetExecutingAssembly().FullName,
             "ConsoleApplication1.LockTest");
            Worker1.Run();

            AppDomain appDomain2 = AppDomain.CreateDomain("AppDomain2");
            LockTest Worker2 = (LockTest)appDomain2.CreateInstanceAndUnwrap(
            Assembly.GetExecutingAssembly().FullName,
            "ConsoleApplication1.LockTest");
            Worker2.Run();
/// <summary>
    /// 跨應(yīng)用程序域邊界或遠程訪問時需要繼承MarshalByRefObject
    /// </summary>
    public class LockTest : MarshalByRefObject
    {
        public void Run()
        {
            lock (typeof(int))
            {
                Thread.Sleep(10000);
                Console.WriteLine(AppDomain.CurrentDomain.FriendlyName + ": Thread 釋放," + DateTime.Now);
            }
        }
    }

運行結(jié)果如下:

第一個例子說明,在同進程同域,不同線程下,鎖type int,其實鎖的是同一個int對象。所以要慎用。

第二個例子,這里就簡單說下。

      A: CLR啟動時,會創(chuàng)建 系統(tǒng)域(System Domain)和共享域(Shared Domain), 默認程序域(Default AppDomain)。 系統(tǒng)域和共享域是單例的。程序域可以有多個,例子中我們使用AppDomain.CreateDomain方法創(chuàng)建的。

      B:  按正常來說,每個程序域的代碼都是隔離,互不影響的。但對于一些基礎(chǔ)類型來說,每個程序域都重新加載一份,就顯得有點浪費,帶來額外的損耗壓力。聰明的CLR會把一些基本類型Object, ValueType, Array, Enum, String, and Delegate等所在的程序集MSCorLib.dll,在CLR啟動過程中都會加載到共享域。  每個程序域都會使用共享域的基礎(chǔ)類型實例。 

      C: 而每個程序域都有屬于自己的托管堆。托管堆中最重要的是GC heap和Loader heap。GC heap用于引用類型實例的存儲,生命周期管理和垃圾回收。Loader heap保存類型系統(tǒng),如MethodTable,數(shù)據(jù)結(jié)構(gòu)等,Loader heap生命周期不受GC管理,跟程序域卸載有關(guān)。

     所以共享域中Loader heap MSCorLib.dll中的int實例會一直保留著,直到進程結(jié)束。單個程序域卸載也不受影響。作用域很大有沒有?。?!

     這時第二個例子也很容易理解了。 鎖int實例是跨程序域的,MSCorLib中的基礎(chǔ)類型都是這樣。 極容易造成死鎖,慎用。  而自定義類型則會加載到自己的程序域,不會影響別人。

3:字符串的鎖

我們都知道鎖的目的,是為了多線程下值被破壞。也知道string在c#是個特殊對象,值是不變的,每次變動都是一個新對象值,這也是推薦stringbuilder原因。如例:

復(fù)制代碼 代碼如下:

//======Example 4=====
        string str1 = "mushroom";
        string str2 = "mushroom";
        var result1 = object.ReferenceEquals(str1, str2);
        var result2 = object.ReferenceEquals(str1, "mushroom");
        Console.WriteLine(result1 + "-" + result2);
        /* output
         * True-True
         */

 正式由于c#中字符串的這種特性,所以字符串是在多線程下是不會被修改的,只讀的。它存在于SystemDomain域中managed heap中的一個hash table中。Key為string本身,Value為string對象的地址。

 當(dāng)程序域需要一個string的時候,CLR首先在這個Hashtable根據(jù)這個string的hash code試著找對應(yīng)的Item。如果成功找到,則直接把對應(yīng)的引用返回,否則就在SystemDomain對應(yīng)的managed heap中創(chuàng)建該 string,并加入到hash table中,并把引用返回。所以說字符串的生命周期是基于整個進程的,也是跨AppDomain。

4:monitor用法

介紹下Wait,Pulse,PulseAll的用法。有注釋,大家直接看代碼吧。

復(fù)制代碼 代碼如下:

static string str = "mushroom";
        static void Main(string[] args)
        {
            new Thread(() =>
            {
                bool isGetLock = false;
                Monitor.Enter(str, ref isGetLock);
                try
                {
                    Console.WriteLine("Thread1第一次獲取鎖");
                    Thread.Sleep(5000);
                    Console.WriteLine("Thread1暫時釋放鎖,并等待其他線程釋放通知信號。");
                    Monitor.Wait(str);
                    Console.WriteLine("Thread1接到通知,第二次獲取鎖。");
                    Thread.Sleep(1000);
                }
                finally
                {
                    if (isGetLock)
                    {
                        Monitor.Exit(str);
                        Console.WriteLine("Thread1釋放鎖");
                    }
                }
            }).Start();
            Thread.Sleep(1000);
            new Thread(() =>
            {
                bool isGetLock = false;
                Monitor.Enter(str, ref isGetLock); //一直等待中,直到其他釋放。
                try
                {
                    Console.WriteLine("Thread2獲得鎖");
                    Thread.Sleep(5000);
                    Monitor.Pulse(str); //通知隊列里一個線程,改變鎖狀態(tài)。  Pulseall 通知所有的
                    Console.WriteLine("Thread2通知其他線程,改變狀態(tài)。");
                    Thread.Sleep(1000);
                }
                finally
                {
                    if (isGetLock)
                    {
                        Monitor.Exit(str);
                        Console.WriteLine("Thread2釋放鎖");
                    }
                }

            }).Start();
            Console.ReadLine();

二:mutex

 lock是不能跨進程鎖的。 mutex作用和lock類似,但是它能跨進程鎖資源(走的是windows內(nèi)核構(gòu)造)。 我們來看個例子
 

復(fù)制代碼 代碼如下:

 static bool createNew = false;
        //第一個參數(shù) 是否應(yīng)擁有互斥體的初始所屬權(quán)。即createNew true時,mutex默認獲得處理信號
        //第二個是名字,第三個是否成功。
        public static Mutex mutex = new Mutex(true, "mushroom.mutex", out createNew);

        static void Main(string[] args)
        {
            //======Example 5=====
            if (createNew)  //第一個創(chuàng)建成功,這時候已經(jīng)拿到鎖了。 無需再WaitOne了。一定要注意。
            {
                try
                {
                    Run();
                }
                finally
                {
                    mutex.ReleaseMutex(); //釋放當(dāng)前鎖。 
                }
            }
            //WaitOne 函數(shù)作用是阻止當(dāng)前線程,直到拿到收到其他實例釋放的處理信號。
            //第一個參數(shù)是等待超時時間,第二個是否退出上下文同步域。
            else if (mutex.WaitOne(10000,false))//
            {
                try
                {
                    Run();
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
            else//如果沒有發(fā)現(xiàn)處理信號
            {
                Console.WriteLine("已經(jīng)有實例了。");
                Console.ReadLine();
            }
        }
        static void Run()
        {
            Console.WriteLine("實例1");
            Console.ReadLine();
        }
 

 我們順序起A  B實例測試下。   A首先拿到鎖,輸出 實例1 。   B在等待, 如果10秒內(nèi)A釋放,B拿到執(zhí)行Run()。  超時后輸出  已經(jīng)有實例了。

這里注意的是第一個拿到處理信號 的實例,已經(jīng)拿到鎖了。不需要再WaitOne。  否則報異常。 

三:Semaphore

 即信號量,我們可以把它理解為升級版的mutex。mutex對一個資源進行鎖,semaphore則是對多個資源進行加鎖。

semaphore是由windows內(nèi)核維持一個int32變量的線程計數(shù)器,線程每調(diào)用一次、計數(shù)器減一、釋放后對應(yīng)加一, 超出的線程則排隊等候。

走的是內(nèi)核構(gòu)造,所以semaphore也是可以跨進程的。

復(fù)制代碼 代碼如下:

static void Main(string[] args)
        {
            Console.WriteLine("準(zhǔn)備處理隊列");

            bool createNew = false;

            SemaphoreSecurity ss = new SemaphoreSecurity(); //信號量權(quán)限控制
            Semaphore semaphore = new Semaphore(2, 2, "mushroom.Semaphore", out createNew,null);
            for (int i = 1; i <= 5; i++)
            {
                new Thread((arg) =>
                {
                    semaphore.WaitOne();
                    Console.WriteLine(arg + "處理中");
                    Thread.Sleep(10000);
                    semaphore.Release(); //即semaphore.Release(1)
                    //semaphore.Release(5);可以釋放多個,但不能超過最大值。如果最后釋放的總量超過本身總量,也會報錯。 不建議使用

                }).Start(i);
            }
            Console.ReadLine();
        }

四:總結(jié)

 mutex、Semaphore  需要由托管代碼轉(zhuǎn)成本地用戶模式代碼、再轉(zhuǎn)換為本地內(nèi)核代碼。 

 反之同樣,饒了一大圈,性能肯定不會很好。所以僅在需要跨進程的場景才使用。

相關(guān)文章

  • C#反序列化到類的實現(xiàn)方法

    C#反序列化到類的實現(xiàn)方法

    這篇文章主要介紹了C#反序列化到類的實現(xiàn)方法,涉及C#反序列化的相關(guān)技巧,需要的朋友可以參考下
    2015-05-05
  • WinForm導(dǎo)出文件為Word、Excel、文本文件的方法

    WinForm導(dǎo)出文件為Word、Excel、文本文件的方法

    這篇文章主要介紹了WinForm導(dǎo)出文件為Word、Excel、文本文件的方法,本文直接給出實現(xiàn)代碼,代碼中包含相應(yīng)注釋,需要的朋友可以參考下
    2015-03-03
  • 基于WPF實現(xiàn)彈幕效果的示例代碼

    基于WPF實現(xiàn)彈幕效果的示例代碼

    這篇文章主要為大家詳細介紹了如何利用WPF實現(xiàn)彈幕效果,文中的示例代碼講解詳細,對我們學(xué)習(xí)或工作有一定幫助,感興趣的小伙伴可以了解一下
    2022-09-09
  • 淺談c# 浮點數(shù)計算

    淺談c# 浮點數(shù)計算

    本文通過具體的示例給大家演示了下C#中浮點數(shù)運算所遇到的問題及解決方法,有需要的小伙伴可以參考下
    2017-09-09
  • VS2019屬性管理器沒有Microsoft.Cpp.x64.user的解決辦法

    VS2019屬性管理器沒有Microsoft.Cpp.x64.user的解決辦法

    這篇文章主要介紹了VS2019屬性管理器沒有Microsoft.Cpp.x64.user的解決辦法,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-03-03
  • WPF TextBox和PasswordBox添加水印

    WPF TextBox和PasswordBox添加水印

    這篇文章主要為大家詳細介紹了WPF TextBox和PasswordBox添加水印的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • Unity切割圖集轉(zhuǎn)換為多張圖片

    Unity切割圖集轉(zhuǎn)換為多張圖片

    這篇文章主要為大家詳細介紹了Unity切割圖集轉(zhuǎn)換為多張圖片,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-07-07
  • 使用C#實現(xiàn)替換文件中的IP地址

    使用C#實現(xiàn)替換文件中的IP地址

    這篇文章主要為大家詳細介紹了如何使用C#來處理一個實際的編程挑戰(zhàn):讀取一個配置文件并替換其中的IP地址,感興趣的小伙伴可以了解下
    2024-01-01
  • C#列出所有物理網(wǎng)絡(luò)適配器的方法

    C#列出所有物理網(wǎng)絡(luò)適配器的方法

    這篇文章主要介紹了C#列出所有物理網(wǎng)絡(luò)適配器的方法,實例分析了C#操作網(wǎng)絡(luò)設(shè)備的技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-04-04
  • C#上位機與三菱PLC通訊的實現(xiàn)步驟(圖文)

    C#上位機與三菱PLC通訊的實現(xiàn)步驟(圖文)

    這篇文章主要介紹了C#上位機與三菱PLC通訊的實現(xiàn)步驟(圖文),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02

最新評論