简体   繁体   中英

C# Threading - lock - how to check lock occurrences

Im using locking object in my application with multiple threads.

How i can check how many times other threads tried to work on locked object, or how much time i wasted on trying to update locked object?

My code is based on best answer here:

Mutliple threads updating array

Edit: code copied over:

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

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

The System.Diagnostics.Stopwatch class may help you here:

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

The question as asked is how to determine the number of times a lock request occurs, or the amount of time wasted due to lock contention.

The answer to the asked question is you use a profiler such as the one supplied with Visual Studio Premium Edition. Other .NET profilers may exist.

It is impractical to add counting/timing code at every lock statement because it would have its own locking issues. So in the absence of a profiler, you must perform a static analysis. This isn't so dire. Nested loops are a big clue.

Lock contention looms largest in server design. Happily, user session state is private to the session. If you're using APM (asynchronous programming model - callbacks, essentially) then provided you don't call socket.BeginRead until the end of your handler, from the point of view of the session, operations on state are effectively single threaded. So under these conditions, locking is necessary only for set up and tear down of a session. Within the session it is completely unnecessary.

This is why I prefer APM over newer and more fashionable ways to handle concurrent execution.

A nice tool to start investigating lock contention is the Concurrency Visualizer as explained here . Don't be afraid about this blog article being from 2010. The same principles still apply in the newer versions of the Concurrency Visualizer for newer version of Visual Studio.

I'm no threading expert, but in order to get the number of times other threads tried to work on the object you'd probably have to implement a more primitive version of a locking mechanism than Lock . I gave it a shot below with a tightly looped Monitor.TryEnter and comments are welcome.

Of course implementing something like this alone could easily result in longer blocking time and more blocks in order both get the counts you want and based on the fact that this implementation is surely not identical to how lock works internally. Anyways I spent the time so I'm going to post it.

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

Above shows you how to use the LockWithCount by replacing your existing Lock() {} with 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);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM