4

我在具有多个线程的应用程序中使用锁定对象。

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

我的代码基于此处的最佳答案:

多线程更新数组

编辑:复制代码:

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

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

4 回答 4

6

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);
于 2012-10-23T22:04:09.490 回答
1

所问的问题是如何确定锁请求发生的次数,或者由于锁争用而浪费的时间量。

所问问题的答案是您使用诸如 Visual Studio 高级版提供的分析器。可能存在其他 .NET 分析器。

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

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

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

于 2012-10-24T01:51:25.190 回答
1

开始调查锁争用的一个很好的工具是并发可视化工具,如此所述。不要害怕这篇博客文章来自 2010 年。同样的原则仍然适用于新版本的 Visual Studio 的并发可视化工具。

于 2017-09-21T13:43:26.670 回答
0

我不是线程专家,但为了获得其他线程尝试处理对象的次数,您可能必须实现比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);
                }
            }
        }
    }

上面向您展示了如何通过将现有的替换为 LockWithCount 来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);
    }
}
于 2012-10-23T22:56:01.063 回答