C#线程-锁定-如何检查锁定事件

C#线程-锁定-如何检查锁定事件,c#,multithreading,.net-3.5,C#,Multithreading,.net 3.5,我在应用程序中使用多线程锁定对象 我如何检查其他线程尝试处理锁定对象的次数,或者我在更新锁定对象上浪费了多少时间 我的代码基于以下最佳答案: 编辑:代码复制到: float[] bestResult; object sync = new Object(); lock (sync) { if (bestResult[0] > calculatedData[0]) { bestResult = calculatedData; } } 本课程可能会在以下方

我在应用程序中使用多线程锁定对象

我如何检查其他线程尝试处理锁定对象的次数,或者我在更新锁定对象上浪费了多少时间

我的代码基于以下最佳答案:

编辑:代码复制到:

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

lock (sync) 
{
    if (bestResult[0] > calculatedData[0]) {
        bestResult = calculatedData;
    }
}
本课程可能会在以下方面帮助您:

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);

我不是线程专家,但为了获得其他线程尝试处理该对象的次数,您可能必须实现比
Lock
更原始的锁定机制。我在下面用一个紧密循环的监视器进行了一次尝试。欢迎输入和评论

当然,单独实现这样的东西很容易导致更长的阻塞时间和更多的阻塞,以便获得您想要的计数,并且基于这样一个事实,即这种实现肯定与锁内部的工作方式不同。反正我花了时间,所以我要把它贴出来

   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);
                }
            }
        }
    }
问题是如何确定锁请求发生的次数,或者由于锁争用而浪费的时间

问题的答案是您使用的探查器,如VisualStudio Premium Edition提供的探查器。可能存在其他.NET探查器

在每个lock语句中添加计数/计时代码是不切实际的,因为它会有自己的锁定问题。因此,在没有分析器的情况下,必须执行静态分析。这并不可怕。嵌套循环是一条重要线索

锁争用是服务器设计中最大的问题。令人高兴的是,用户会话状态对会话是私有的。如果您使用的是APM(异步编程模型,本质上是回调),那么从会话的角度来看,只要在处理程序结束之前不调用socket.BeginRead,状态操作实际上是单线程的。因此,在这些条件下,锁定仅在会话的设置和中断时才有必要。在会话中,这是完全不必要的


这就是为什么我更喜欢使用APM而不是更新、更时尚的方法来处理并发执行。

一个很好的开始调查锁争用的工具就是前面解释的。不要担心这篇博客文章来自2010年。对于较新版本的Visual Studio,相同的原则仍然适用于较新版本的并发可视化工具。

忙于等待锁是高度CPU密集型的。这将起作用,但如果锁被轻易地争用,它将破坏性能。一个更好的解决方案是使用一个
监视器。TryEnter
,如果失败,设置
阻塞
标志并执行
监视器。输入
@Jim Mischel好主意,这将使它在实际等待时,在实现过程中与锁非常接近。我会更新。尽管我在下面给出了答案,但如果您想在没有分析器的情况下测量这一点,那么FMM是我能看到的唯一实用的答案。如果您正在探索整个并发问题,您可能会发现这很方便。这是“C#5.0简而言之”中关于线程的完整部分,感谢您的回复。我从来没有在.NET中使用过像Profiler这样的工具,我不知道在我的VS2008标准版中是否有这样的工具。我认为@FMM回复对我来说已经足够了。
 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);
    }
}