2011-05-27 22 views
8

我發佈我對C#鎖的理解如下,請幫助我驗證我是否正確。C#鎖關鍵字的用法

public class TestLock 
{ 
    private object threadLock = new object(); 
    ... 
    public void PrintOne() 
    { 
     lock (threadLock) 
     { 
      // SectionOne 
     } 
    } 

    public void PrintTwo() 
    { 
     lock (threadLock) 
     { 
      // SectionTwo 
     } 
    } 
    ... 
} 

案例I>線程1和線程同時試圖調用PrintOne。 由於PrintOne由實例鎖保護,因此在任何時候,只有一個線程可以專門進入SectionOne。

這是正確的嗎?

案例二>線程1和線程同時嘗試分別撥打PrintOne和PrintTwo (即線程1調用PrintOne及線程調用PrintTwo) 由於兩個打印方法是由同一個實例鎖保護,在任何時候, 只有一個線程可以獨佔訪問SectionOne或SectionTwo,但不能同時訪問兩者。

這是正確的嗎?

+1

總結如下答案:代碼是線程安全的僅爲實例。當實例共享資源時,@oleski有正確答案(=否) – 2011-05-27 22:15:57

+0

因此-1不包含共享數據/資源。請編輯。 – 2011-05-27 22:21:19

+2

這是一個有效的觀點,但最初的問題並沒有說明這些實例是否是單獨的,因此,從編寫代碼/問題的方式來看,假設他正在討論針對同一實例進行的調用是安全的。所以,我不同意你的失望,但那是你的代表。 – 2011-05-27 22:43:21

回答

1

是的,是的。案件是正確的。

+0

代碼是線程不安全的 – oleksii 2011-05-27 21:54:23

+0

@oleksii:就像你說的那樣,只是每個實例都是安全的。然而OP寫的關於實例鎖。 – 2011-05-27 22:25:08

+0

我猜@亨克是有道理的,在這個特定的問題上,這個問題很模糊 – oleksii 2011-05-27 22:34:16

1

案例一:檢查✓

案例二:檢查✓

不要忘了鎖是線程同步的一種方式。對於其他userfull方法,請閱讀:Thread Synchronization

直接從MSDN樣本:

public class TestThreading 
{ 
    private System.Object lockThis = new System.Object(); 

    public void Process() 
    {  
     lock (lockThis) 
     { 
      // Access thread-sensitive resources. 
     } 
    }  
} 
+4

我的建議:http://www.albahari.com/threading/ – 2011-05-27 21:25:22

+0

鎖定對象不是靜態的,代碼是線程不安全 – oleksii 2011-05-27 21:55:29

+0

@Teoman請試試我的示例代碼,你將得到一個IOException,文件用來。我相信這是一個有效的例子。鎖定對象**必須是靜態的。如果兩個線程使用該類的不同實例,則會有兩個鎖定實例,並且該代碼變爲線程不安全。 – oleksii 2011-05-27 22:04:39

1

你的理解是100%正確的。因此,例如,如果你想允許分別進入兩種方法,你會想要兩個鎖。

+0

+1 for _「允許分別進入兩種方法,您希望有兩個鎖」_ – 2011-05-27 23:09:51

6

1和2 真的只有如果所有的線程使用類的相同實例。如果他們使用不同的實例,那麼這兩種情況

樣品

public class TestLock 
{ 
    private object threadLock = new object(); 

    public void PrintOne() 
    { 
     lock (threadLock) 
     { 
      Console.WriteLine("One"); 
      var f = File.OpenWrite(@"C:\temp\file.txt"); //same static resource 
      f.Close(); 
     } 
    } 

    public void PrintTwo() 
    { 
     lock (threadLock) 
     { 
      Console.WriteLine("Two"); 
      var f = File.OpenWrite(@"C:\temp\file.txt"); //same static resource 
      f.Close(); 
     } 
    } 
} 

並測試代碼

static void Main(string[] args) 
{ 
    int caseNumber = 100; 

    var threads = new Thread[caseNumber]; 
    for (int i = 0; i < caseNumber; i++) 
    { 
     var t = new Thread(() => 
           { 
            //create new instance 
            var testLock = new TestLock(); 
            //for this instance we safe 
            testLock.PrintOne(); 
            testLock.PrintTwo(); 
           }); 
     t.Start(); 
     //once created more than one thread, we are unsafe 
    } 
} 

一個可能的解決方案是一個靜態的關鍵字添加到鎖定對象聲明和使用它的方法。

private static object threadLock = new object(); 

UPDATE 好一點的konrad.kruczynski

做...... 「線程安全」 也從 方面承擔。例如,我可以採取 您的文件開放代碼,並且 生成異常與靜態鎖 - 只需要另一個應用程序 域。因此建議OP 應該使用全系統互斥類或 這樣的。因此,靜態情況 只是推斷爲實例一。

+0

代碼是線程安全的_per instance_。 OP提到「實例鎖定」一次,但對實際共享的內容含糊不清。 – 2011-05-27 22:14:25

+0

@亨克我同意他提到實例鎖定,將更新我的答案。 TNX。 – oleksii 2011-05-27 22:18:42

+3

鎖性能與鎖有多少爭用非常直接相關。所以你真的不應該使用靜態鎖,除非你正在修改靜態數據,並且如果你正在使用靜態鎖,除了保護靜態數據外,你不應該使用靜態鎖。 – Yaur 2011-05-27 22:39:15

0

這裏是基本知識(或多或少)

1)使用實例鎖例如數據

public class InstanceOnlyClass{ 
    private int callCount; 
    private object lockObject = new object(); 

    public void CallMe() 
    { 
     lock(lockObject) 
     { 
      callCount++; 
     } 
    } 
} 

2)使用靜態數據

public class StaticOnlyClass{ 
    private int createdObjects; 
    private static object staticLockObject = new object(); 

    public StaticOnlyClass() 
    { 
     lock(staticLockObject) 
     { 
      createdObjects++; 
     } 
    } 
} 

3靜態鎖)如果您保護靜態數據和實例數據使用單獨的靜態和實例鎖

public class StaticAndInstanceClass{ 
    private int createdObjects; 

    private static object staticLockObject = new object(); 

    private int callCount; 

    private object lockObject = new object(); 

    public StaticAndInstanceClass() 
    { 
     lock(staticLockObject) 
     { 
      createdObjects++; 
     } 
    } 

    public void CallMe() 
    { 
     lock(lockObject) 
     { 
      callCount++; 
     } 
    } 
} 

在此基礎上你的代碼是好的,如果你正在訪問實例數據,但不安全的,如果你正在修改靜態數據