当锁没有争用时,锁(...)有多贵?

时间:2012-01-09 12:31:48

标签: c# concurrency synchronization locking

在查看双重检查锁定时,我看到了许多建议,只是跳过第一次检查并立即进行锁定,然后检查后再进行检查。

这让我想知道,lock (this.padlock)在没有竞争时“便宜”吗?

3 个答案:

答案 0 :(得分:24)

我们可以测试一下......

我明白了:

1000000000; 2164 (no lock)
1000000000; 23258 (lock)
21.094ns per lock

代码:

using System;
using System.Diagnostics;

static class P
{
    static void Main()
    {

        Test(1); // for JIT
        Test(1000000);
    }
    static readonly object syncLock = new object();
    static void Test(int count)
    {
        int j = 0;
        var watch = Stopwatch.StartNew();
        for(int i = 0 ; i < count ; i++)
        {
            for (int z = 0; z < 1000; z++)
                j++;
        }
        watch.Stop();
        long withoutMillis = watch.ElapsedMilliseconds;
        Console.WriteLine("{0}; {1} (no lock)", j, watch.ElapsedMilliseconds);

        j = 0;
        watch = Stopwatch.StartNew();
        for (int i = 0; i < count; i++)
        {
            for (int z = 0; z < 1000; z++ )
                lock (syncLock)
                {
                    j++;
                }
        }
        watch.Stop();
        long withMillis = watch.ElapsedMilliseconds;
        Console.WriteLine("{0}; {1} (lock)", j, watch.ElapsedMilliseconds);

        long deltaNano = (withMillis - withoutMillis) * 1000000;
                // nano = 1000 micro = 1000000 milli
        double perLockNano = deltaNano/(1000.0 * count);
        Console.WriteLine("{0}ns per lock", perLockNano);
    }
}

答案 1 :(得分:10)

根据this source,锁定和解锁的开销约为20ns。

答案 2 :(得分:2)

我写得很快并且没有对它进行过测试,我发布它只是为了传达一般的想法,一种方法来使用扩展方法,使用扩展方法和委托或lambda函数。我也不能不经测试,如果这会弄巧成拙,这当然是可能的。

我有在多线程进程中运行的代码,以及使用协作光纤模式线程模型的进程(例如,有多个线程永远不会异步执行)。在协作光纤模式应用程序中,锁定是毫无意义和浪费的,因此这可能是在必须完成锁定的每个点上避免大量混乱逻辑的解决方案。

// Conditional Locking concept code

namespace SystemExtensions {

public static class LockMeUp
{
  private static bool isLockingEnabled = true;

  // If set to true, locking will be performed
  // by the extension methods below.

  internal static bool LockingEnabled
  {
    get
    {
      return isLockingEnabled;
    }
    set
    {
      isLockingEnbaled = value;
    }
  }

  static void CheckNull<TLock>( TLock target ) where TLock: class
  {
    if( target == null )
      throw new ArgumentNullException("target cannot be null");
  }

  // Invoke the supplied action on the supplied lock object

  public static void TryLock<TLock>( 
    this TLock target, 
    Action<TLock> action ) where TLock: class
  {
    CheckNull( target );
    if( isLockingEnabled )
    {
      lock( target )
      {
        action( target );
      }
    }
    else
    {
      action( target );
    }
  }

  // Invoke the supplied function on the supplied 
  // lock object and return result:   

  public static T TryLock<TLock, T>( 
    this TLock target, 
    Func<TLock, T> func ) where TLock: class
  {
    CheckNull( target );
    if( isLockingEnabled )
    {
      lock( target )
      {
        return func( target );
      }
    }
    else
    {
      return func( target );
    }
  }

  // Invoke the supplied function on the supplied lock object 
  // and another supplied argument, and return the result:    

  public static T TryLock<TLock, TArg, T>( 
    this TLock target, 
    Func<TLock, TArg, T> func, 
    TArg arg ) where TLock: class
  {
    CheckNull( target );
    if( isLockingEnabled )
    {
      lock( target )
      {
        return func( target, arg );
      }
    }
    else
    {
      return func( target, arg );
    }
  }

  // Invoke the supplied action on the supplied lock object 
  // and another supplied argument:   

  public static void TryLock<TLock, TArg>( 
    this TLock target, 
    Action<TLock, TArg> func, 
    TArg arg )  where TLock: class
  {
    CheckNull( target );
    if( isLockingEnabled )
    {
      lock( target )
      {
        func( target, arg );
      }
    }
    else
    {
      func( target, arg );
    }
  } 
}

///// Example:

public static class SharedList<T>
{
  private static List<T> items = new List<T>();

  public static bool Remove( T item )
  {
    return items.TryLock( (list, item) => list.Remove( item ), item );
  }

  public static T GetItemAt( int index )
  {
    return items.TryLock( (list, i) => list[i], index );
  }

  public static bool Contains( T item )
  {
    return items.TryLock( (list, it) => list.Contains( it ), item );
  }

  public static void Add( T item )
  {
    items.TryLock( (list, item) => list.Add( item ) );
  }
}

} // namespace