首页 > 技术文章 > C# 多线程互斥锁

lewisli 2014-03-07 15:10 原文

lock    關鍵字可將陳述式區塊標記為關鍵區段 (Critical Section),其做法是為指定的物件取得互斥鎖定、執行陳述式,接著釋出該鎖定。             下列範例包含一個 lock 陳述式。

 1     class Account
 2     {
 3         decimal balance;
 4         private Object thisLock = new Object();
 5 
 6         public void Withdraw(decimal amount)
 7         {
 8             lock (thisLock)
 9             {
10                 if (amount > balance)
11                 {
12                     throw new Exception("Insufficient funds");
13                 }
14                 balance -= amount;
15             }
16         }
17     }

 

備註            

            
          

lock   關鍵字可保證有執行緒在關鍵區段時,絕對不會有任何其他執行緒同時也進入這個關鍵區段執行。               如果其他執行緒嘗試進入已鎖定的程式碼,它將會等候、封鎖,直到該物件被釋出。 

執行緒 (C# 和 Visual Basic)   這一章節會討論執行緒的處理。                       

lock   關鍵字會在區塊開始執行時呼叫 Enter,並在區塊結束時呼叫 Exit。               ThreadInterruptedException   擲回,如果 Interrupt 中斷等待進入 lock 陳述式的執行緒。 

一般而言,請避免鎖定 public 型別或程式碼無法控制的執行個體。               有三種常見的建構,分別為 lock (this)lock (typeof (MyType))lock ("myLock"),違反這項方針: 

  • lock (this) 在可公開存取執行個體的情況下,會是問題所在。                               

  • lock (typeof (MyType)) 在可公開存取 MyType 的情況下,會是問題所在。                               

  • lock("myLock") 會是問題所在,因為使用相同字串的處理序中若有任何其他程式碼,將會共用相同的鎖定。                               

最佳作法是定義要鎖定的 private 物件,或者定義 private static 物件變數保護所有執行個體通用的資料。                       

您在 lock 陳述式的主體中不能使用 等候 關鍵字。                        

範例            

以下的範例顯示在 C# 中執行緒 (但不用鎖定) 的簡易用法。    
    //using System.Threading;

    class ThreadTest
    {
        public void RunMe()
        {
            Console.WriteLine("RunMe called");
        }

        static void Main()
        {
            ThreadTest b = new ThreadTest();
            Thread t = new Thread(b.RunMe);
            t.Start();
        }
    }
    // Output: RunMe called

下列範例使用到執行緒與 lock。               只要 lock 陳述式存在,此陳述式區塊就是關鍵區段,而且 balance 永遠不會成為負數。

 1     // using System.Threading;
 2 
 3     class Account
 4     {
 5         private Object thisLock = new Object();
 6         int balance;
 7 
 8         Random r = new Random();
 9 
10         public Account(int initial)
11         {
12             balance = initial;
13         }
14 
15         int Withdraw(int amount)
16         {
17 
18             // This condition never is true unless the lock statement
19             // is commented out.
20             if (balance < 0)
21             {
22                 throw new Exception("Negative Balance");
23             }
24 
25             // Comment out the next line to see the effect of leaving out 
26             // the lock keyword.
27             lock (thisLock)
28             {
29                 if (balance >= amount)
30                 {
31                     Console.WriteLine("Balance before Withdrawal :  " + balance);
32                     Console.WriteLine("Amount to Withdraw        : -" + amount);
33                     balance = balance - amount;
34                     Console.WriteLine("Balance after Withdrawal  :  " + balance);
35                     return amount;
36                 }
37                 else
38                 {
39                     return 0; // transaction rejected
40                 }
41             }
42         }
43 
44         public void DoTransactions()
45         {
46             for (int i = 0; i < 100; i++)
47             {
48                 Withdraw(r.Next(1, 100));
49             }
50         }
51     }
52 
53     class Test
54     {
55         static void Main()
56         {
57             Thread[] threads = new Thread[10];
58             Account acc = new Account(1000);
59             for (int i = 0; i < 10; i++)
60             {
61                 Thread t = new Thread(new ThreadStart(acc.DoTransactions));
62                 threads[i] = t;
63             }
64             for (int i = 0; i < 10; i++)
65             {
66                 threads[i].Start();
67             }
68         }
69     }

 

        

推荐阅读