Подтвердить что ты не робот

Насколько дорого стоит блокировка (...), когда блокировка не разрешена?

При просмотре блокировки с двойным проверкой я видел многочисленные рекомендации, чтобы просто пропустить первую проверку и сразу перейти к блокировке и просто проверить, не приняв ее.

Это заставило меня задаться вопросом: lock (this.padlock) "дешево", когда вы не уверены?

4b9b3361

Ответ 1

Мы можем проверить его...

Я получаю:

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

Ответ 2

Согласно этот источник, накладные расходы для блокировки и разблокировки составляют около 20 нс.

Ответ 3

Я написал это очень быстро и не тестировал его, и я отправляю его только для того, чтобы передать общую идею, один подход к условной блокировке, используя методы расширения, делегаты или лямбда-функции. Я также не могу сказать без тестирования, если это будет самопровозглашение, что, безусловно, возможно.

У меня есть код, который работает как в процессах с несколькими потоками, так и в процессах, использующих модель поточного моделирования кооперативного оптоволокна (например, если существует несколько потоков, которые никогда не выполняются асинхронно). В приложении кооперативного режима волокна блокировка бессмысленна и расточительна, поэтому это может быть решением, позволяющим избежать множества беспорядочной логики в каждой точке, где необходимо выполнить блокировку.

// 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