2012-10-23 29 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。