2012-10-23 57 views
4

在我的應用程序中使用鎖定對象與多個線程。C#線程 - 鎖 - 如何檢查鎖定發生

我可以檢查其他線程試圖在鎖定的對象上工作多少次,或者我試圖更新鎖定的對象時浪費了多少時間?

我的代碼是基於最好的答案在這裏:

Mutliple threads updating array

編輯:代碼複製過來:

float[] bestResult; 
object sync = new Object(); 

lock (sync) 
{ 
    if (bestResult[0] > calculatedData[0]) { 
     bestResult = calculatedData; 
    } 
} 

回答

5

System.Diagnostics.Stopwatch類可以幫助你在這裏:

float[] bestResult; 
object sync = new Object(); 
var sw = new System.Diagnostics.Stopwatch(); 
sw.Start(); 

lock (sync) 
{ 
    sw.Stop(); 
    if (bestResult[0] > calculatedData[0]) { 
     bestResult = calculatedData; 
    } 
} 

Console.WriteLine("Time spent waiting: " + sw.Elapsed); 
+0

儘管我的回答如下,但如果您想在沒有探查器的情況下測量這個*,FMM有我能看到的唯一實際答案。 –

+0

如果您正在研究整個併發性問題,您可能會發現這一點很方便。這是關於「C#5.0 In A Null Shell」線程的整個部分http://www.albahari.com/threading/ –

0

我不是線程專家,但爲了獲得更多的時間es其他線程試圖在對象上工作,您可能必須實現比Lock更加原始版本的鎖定機制。我用一個緊密環繞的Monitor.TryEnter對它進行了一些處理,並歡迎評論。

當然,單獨實現這樣的東西很容易導致更長的阻塞時間和更多的塊,以便獲得您想要的計數,並基於事實上該實現肯定不同於內部鎖的工作方式。無論如何,我花了時間,所以我會發布它。

class Program 
    { 
     static object lockObj = new object(); 
     static void Main(string[] args) 
     { 
      System.Threading.Thread t = new System.Threading.Thread(proc); 
      System.Threading.Thread t2 = new System.Threading.Thread(proc); 
      t.Start(); 
      t2.Start(); 
      t.Join(); 
      t2.Join(); 
      Console.WriteLine("Total locked up time = " + (LockWithCount.TotalWaitTicks/10000) + "ms"); 
      Console.WriteLine("Total blocks = " + LockWithCount.TotalBlocks); 
      Console.ReadLine(); 
     } 

     static void proc() 
     { 
      for (int x = 0; x < 100; x++) 
      { 
       using (new LockWithCount(lockObj)) 
       { 
        System.Threading.Thread.Sleep(10); 
       } 
      } 
     } 
    } 

上面展示瞭如何通過替換現有的Lock() {}using(new LockWithCount(x)) {}

class LockWithCount : IDisposable 
{ 
    static System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); 
    object lockObj; 
    public static long TotalWaitTicks = 0; 
    public static long TotalBlocks = 0; 
    static LockWithCount() 
    { 
     watch.Start(); 
    } 

    public LockWithCount(object obj) 
    { 
     lockObj = obj; 
     long startTicks = watch.ElapsedTicks; 
     if (!System.Threading.Monitor.TryEnter(lockObj)) 
     { 
      System.Threading.Interlocked.Increment(ref TotalBlocks); 
      System.Threading.Monitor.Enter(lockObj); 
      System.Threading.Interlocked.Add(ref TotalWaitTicks, watch.ElapsedTicks - startTicks); 
     } 
    } 


    public void Dispose() 
    { 
     System.Threading.Monitor.Exit(lockObj); 
    } 
} 
+0

忙於等待鎖定的CPU佔用率高。這會起作用,但如果鎖甚至輕微競爭,它將會導致性能下降。一個更好的解決辦法是做一個'Monitor.TryEnter',如果失敗,設置'blocked'標誌並執行'Monitor.Enter'。 –

+0

@Jim Mischel不錯的主意,它會像鎖一樣保持非常接近的效果,就像實際執行時一樣。我會更新。 – deepee1

1

問題如問是如何確定的鎖請求發生的次數,或使用LockWithCount的由於爭用鎖而浪費的時間量。

被問到的問題的答案是您使用的分析器如Visual Studio Premium Edition附帶的分析器。其他.NET分析器可能存在。

在每個鎖定語句中添加計數/計時代碼是不切實際的,因爲它會有自己的鎖定問題。因此,在沒有探查器的情況下,您必須執行靜態分析。這並不太可怕。嵌套循環是一個很大的線索。

服務器設計中最大的鎖爭用織機。令人高興的是,用戶會話狀態對會話是私有的。如果您使用的是APM(異步編程模型 - 本質上是回調函數),那麼假設您不會調用socket.BeginRead直到您的處理程序結束,從會話的角度來看,有關狀態的操作實際上是單線程的。所以在這些條件下,只有在設置和拆除會話時才需要鎖定。在會議中,這是完全沒有必要的。

這就是爲什麼我更喜歡APM而不是更新更時尚的方式來處理併發執行。

+0

感謝您的回覆。我從來沒有在.NET中使用過類似工具,我不知道VS2008標準版中是否有這樣的工具。我認爲@FMM回覆對我來說已經足夠了。 – Kamil

0

一個很好的工具來開始調查鎖爭用是Concurrency Visualizer如解釋here。不要害怕這篇博客文章來自2010年。相同的原則仍然適用於較新版本的Visual Studio的新版本的Concurrency Visualizer。