程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C#多線程編程中的鎖體系根本用法

C#多線程編程中的鎖體系根本用法

編輯:C#入門知識

C#多線程編程中的鎖體系根本用法。本站提示廣大學習愛好者:(C#多線程編程中的鎖體系根本用法)文章只能為提供參考,不一定能成為您想要的結果。以下是C#多線程編程中的鎖體系根本用法正文


平凡在多線程開辟中,總防止不了線程同步。本篇就對net多線程中的鎖體系做個簡略描寫。

目次
一:lock、Monitor
     1:基本。
     2: 感化域。
     3:字符串鎖。
     4:monitor應用
二:mutex
三:Semaphore
四:總結

一:lock、Monitor

1:基本

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

//======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參數是Framework  4.0後新加的。 為了使法式在一切情形下都可以或許肯定,能否有需要釋放鎖。例: Monitor.Enter拿不到鎖

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

2:感化域

     一:Lock是只能在過程內鎖,不克不及跨過程。走的是混雜結構,先自旋再轉成內核結構。

     二:關於對type類型的鎖。以下:

//======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釋放");
            }

運轉成果以下:

我們在來看個例子。

//======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>
    /// 跨運用法式域界限或長途拜訪時須要繼續MarshalByRefObject
    /// </summary>
    public class LockTest : MarshalByRefObject
    {
        public void Run()
        {
            lock (typeof(int))
            {
                Thread.Sleep(10000);
                Console.WriteLine(AppDomain.CurrentDomain.FriendlyName + ": Thread 釋放," + DateTime.Now);
            }
        }
    }

運轉成果以下:

第一個例子解釋,在同過程同域,分歧線程下,鎖type int,其實鎖的是統一個int對象。所以要慎用。

第二個例子,這裡就簡略說下。

      A: CLR啟動時,會創立 體系域(System Domain)和同享域(Shared Domain), 默許法式域(Default AppDomain)。 體系域和同享域是單例的。法式域可以有多個,例子中我們應用AppDomain.CreateDomain辦法創立的。

      B:  按正常來講,每一個法式域的代碼都是隔離,互不影響的。但關於一些基本類型來講,每一個法式域都從新加載一份,就顯得有點糟蹋,帶來額定的消耗壓力。聰慧的CLR會把一些根本類型Object, ValueType, Array, Enum, String, and Delegate等地點的法式集MSCorLib.dll,在CLR啟動進程中都邑加載到同享域。  每一個法式域都邑應用同享域的基本類型實例。 

      C: 而每一個法式域都有屬於本身的托管堆。托管堆中最主要的是GC heap和Loader heap。GC heap用於援用類型實例的存儲,性命周期治理和渣滓收受接管。Loader heap保留類型體系,如MethodTable,數據構造等,Loader heap性命周期不受GC治理,跟法式域卸載有關。

     所以同享域中Loader heap MSCorLib.dll中的int實例會一向保存著,直到過程停止。單個法式域卸載也不受影響。感化域很年夜有無!!!

     這時候第二個例子也很輕易懂得了。 鎖int實例是跨法式域的,MSCorLib中的基本類型都是如許。 極輕易形成逝世鎖,慎用。  而自界說類型則會加載到本身的法式域,不會影響他人。

3:字符串的鎖

我們都曉得鎖的目標,是為了多線程下值被損壞。也曉得string在c#是個特別對象,值是不變的,每次更改都是一個新對象值,這也是推舉stringbuilder緣由。如例:

//======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對象的地址。

 當法式域須要一個string的時刻,CLR起首在這個Hashtable依據這個string的hash code試著找對應的Item。假如勝利找到,則直接把對應的援用前往,不然就在SystemDomain對應的managed heap中創立該 string,並參加到hash table中,並把援用前往。所以說字符串的性命周期是基於全部過程的,也是跨AppDomain。

4:monitor用法

引見下Wait,Pulse,PulseAll的用法。有正文,年夜家直接看代碼吧。

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); //告訴隊列裡一個線程,轉變鎖狀況。  Pulseall 告訴一切的
                    Console.WriteLine("Thread2告訴其他線程,轉變狀況。");
                    Thread.Sleep(1000);
                }
                finally
                {
                    if (isGetLock)
                    {
                        Monitor.Exit(str);
                        Console.WriteLine("Thread2釋放鎖");
                    }
                }

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

二:mutex

 lock是不克不及跨過程鎖的。 mutex感化和lock相似,然則它能跨過程鎖資本(走的是windows內核結構)。 我們來看個例子
 
 static bool createNew = false;
        //第一個參數 能否應具有互斥體的初始所屬權。即createNew true時,mutex默許取得處置旌旗燈號
        //第二個是名字,第三個能否勝利。
        public static Mutex mutex = new Mutex(true, "mushroom.mutex", out createNew);

        static void Main(string[] args)
        {
            //======Example 5=====
            if (createNew)  //第一個創立勝利,這時候候曾經拿到鎖了。 無需再WaitOne了。必定要留意。
            {
                try
                {
                    Run();
                }
                finally
                {
                    mutex.ReleaseMutex(); //釋放以後鎖。 
                }
            }
            //WaitOne 函數感化是阻攔以後線程,直到拿到收到其他實例釋放的處置旌旗燈號。
            //第一個參數是期待超不時間,第二個能否加入高低文同步域。
            else if (mutex.WaitOne(10000,false))//
            {
                try
                {
                    Run();
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
            else//假如沒有發明處置旌旗燈號
            {
                Console.WriteLine("曾經有實例了。");
                Console.ReadLine();
            }
        }
        static void Run()
        {
            Console.WriteLine("實例1");
            Console.ReadLine();
        }
 

 我們次序起A  B實例測試下。   A起首拿到鎖,輸入 實例1 。   B在期待, 假如10秒內A釋放,B拿到履行Run()。  超時後輸入  曾經有實例了。

這裡留意的是第一個拿隨處理旌旗燈號 的實例,曾經拿到鎖了。不須要再WaitOne。  不然報異常。 

三:Semaphore

 即旌旗燈號量,我們可以把它懂得為進級版的mutex。mutex對一個資本停止鎖,semaphore則是對多個資本停止加鎖。

semaphore是由windows內核保持一個int32變量的線程計數器,線程每挪用一次、計數器減1、釋放後對應加一, 超越的線程則列隊等待。

走的是內核結構,所以semaphore也是可以跨過程的。


static void Main(string[] args)
        {
            Console.WriteLine("預備處置隊列");

            bool createNew = false;

            SemaphoreSecurity ss = new SemaphoreSecurity(); //旌旗燈號量權限掌握
            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();
        }

四:總結

 mutex、Semaphore  須要由托管代碼轉本錢地用戶形式代碼、再轉換為當地內核代碼。 

 反之異樣,饒了一年夜圈,機能確定不會很好。所以僅在須要跨過程的場景才應用。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved