C#中的lock關鍵字有何作用

來源:互聯網
上載者:User

標籤:

  作為C#的程式員來說,在遇到線程同步的需求時最常用的就是lock關鍵字。但如何正確並有效地使用lock,卻是能否高效地達到同步要求的關鍵。正因為如此,程式員需要完全理解lock究竟為程式做了什麼。

  所涉及的知識點

• lock的等效代碼

• System.Threading.Monitor類型的作用和使用方法

  分析問題

1.lock的等效代碼

  在.NET的多線程程式中,經常會遇到lock關鍵字來控制同步,比如下列代碼:

private object o = new object();

public void Work()

{

  lock(o)

  {

    //做一些需要線程同步的工作

  }

}

  事實上,lock這個關鍵字是C#為方便程式員而定義的文法,它等效於安全地使用System.Threading.Monitor類型。上面的代碼就直接等效於下面的代碼:

private object o = new object();

public void Work()

{

  //這裡很重要,是為了避免直接使用私人成員o,而導致線程不安全

  object temp = o;

  System.Threading.Monitor.Enter(temp);

  try

  {

    //做一些需要線程同步的工作

  }

  finally

  {

    System.Threading.Monitor.Exit(temp);

  }

}

  正如你看到的,真正實現了線程同步功能的,就是System.Threading.Monitor類型,lock關鍵字只是用來代替調用Enter、Exit方法,並且將所有的工作包含在try塊內,以保證其最終退出同步。

2.System.Threading.Monitor類型的作用和使用

  在前文中已經提到了,Monitor類型的Enter和Exit方法用來實現進入和退出對象的同步。具體來說,當Enter方法被調用時,對象的同步索引將被檢查,並且.NET將負責一系列的後續工作,來保證對象訪問時線程的同步,而Exit方法的調用,則保證了當前線程釋放該對象的同步塊。

  樣本

  下列示範了自訂的類如何利用lock關鍵字(也就是Monitor類型)來實現線程同步,具體定義了一個包含需要同步執行方法的類型。

/// <summary>

/// 示範同步鎖

/// </summary>

public class MyLock

{

    //用來在靜態方法中同步

    private static object o1 = new object();

    //用來在成員方法中不同

    private object o2 = new object();

    //成員變數

    private static int i1 = 0;

    private int i2 = 0;

    /// <summary>

    /// 測試靜態方法的同步

    /// </summary>

    /// <param name=" handleObject ">同步時操作的對象</param>

    public static void Increment1(object handleObject)

    {

        lock (o1)

        {

            Console.WriteLine("i1的值為:{0}", i1);

            //這裡刻意製造線程並行機會,來檢查同步的功能

            Thread.Sleep(200);

            i1++;

            Console.WriteLine("i1自增後為:{0}", i1);

        }

    }

    /// <summary>

    /// 測試成員方法的同步

    /// </summary>

    /// <param name=" handleObject ">同步時操作的對象</param>

    public void Increment2(object handleObject)

    {

        lock (o2)

        {

            Console.WriteLine("i2的值為:{0}", i2);

            //這裡刻意製造線程並行機會,來檢查同步的功能

            Thread.Sleep(200);

            i2++;

            Console.WriteLine("i2自增後為:{0}", i2);

        }

    }

}

 

這樣在main方法中,調用該類型對象的方法和其靜態方法,測試其同步的效果。代碼如下

/// <summary>

/// 程式入口

/// </summary>

class Program

{

  /// <summary>

   /// 測試同步效果

   /// </summary>

  static void Main(string[] args)

  {

         //開始多線程

         Console.WriteLine("開始測試靜態方法的同步");

         for (int i = 0; i < 5; i++)

         {

             Task t = new Task(MyLock.Increment1, i);

             t.Start();

         }

         //這裡等待線程執行結束

        Thread.Sleep(3 * 1000);

         Console.WriteLine("開始測試成員方法的同步");

         MyLock myLock = new MyLock();

         //開始多線程

         for (int i = 0; i < 5; i++)

        {

             Thread t = new Thread(myLock.Increment2);

             t.Start();

         }

         Console.Read();

  }

}

下面是程式的執行結果:

開始測試靜態方法的同步

i1的值為:0

i1自增後為:1

i1的值為:1

i1自增後為:2

i1的值為:2

i1自增後為:3

i1的值為:3

i1自增後為:4

i1的值為:4

i1自增後為:5

開始測試成員方法的同步

i2的值為:0

i2自增後為:1

i2的值為:1

i2自增後為:2

i2的值為:2

i2自增後為:3

i2的值為:3

i2自增後為:4

i2的值為:4

i2自增後為:5

 

   總結

  可以看到,線程同步被很好地保證了。這裡需要強調的是,線程同步本身違反了多線程並行啟動並執行原則,所以讀者在使用線程同步時應該盡量做到把lock加在最小的程式塊上。如果一個方法有大量的代碼需要線程同步,那就需要重新考慮程式的設計了,是否真的有必要進行多執行緒,畢竟線程本身的開銷也是相當大的。

  對靜態方法的同步,一般採用靜態私人的引用成員,而對成員方法的同步,一般採用私人的引用成員。讀者需要注意靜態和非靜態成員的使用,都把同步對象申明為私人,這是保證線程同步高效並且正確的關鍵點。

 

說明:以上內容是根據網上內容進行整理。

C#中的lock關鍵字有何作用

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.