Где правильное место, чтобы использовать замок - PullRequest
3 голосов
/ 20 октября 2011

Я пытаюсь найти лучшее сходство в многопоточной среде.

Есть ли лучшая альтернатива или обе версии одинаковые ниже?

 // float bestSimilarity is shared
 // float _similarity is local

 lock(locker) 
     if (_similarity > bestSimilarity)
         bestSimilarity = _similarity;

против

 if (_similarity > bestSimilarity)
     lock(locker) 
         bestSimilarity = _similarity;

Ответы [ 5 ]

7 голосов
/ 20 октября 2011

Ваш первый случай будет работать гарантированно.Второй случай, однако, может сломаться.Вы сравниваете, а затем запрашиваете блокировку, в то время как другой поток уже изменяет bestShapsity, и вы не знаете, что это делает сравнение недействительным.

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

2 голосов
/ 20 октября 2011

Поскольку bestSimilarity является общим, вам нужно будет использовать первый сегмент кода

1 голос
/ 20 октября 2011

Вы также можете сделать это без блокировки:

bool retry;
do
{
    retry = false;
    var copy = Interlocked.CompareExchange(ref bestSimilarity, 0, 0);

    if (_similarity > copy)
    {
        retry = Interlocked.CompareExchange(
              ref bestSimilarity, _similarity, copy) != copy;
    }
} while (retry);

Это:

  • делает снимок bestSimilarity в начале (я предполагаю, что это аккумулятор)
  • затем сравнивает наше текущее значение (_similarity) со снимком (который стабилен как локальный)
  • если оно выше, оно меняет значение , но только если аккумулятор не изменился
  • если аккумулятор изменил , он снова все сделает

Это полностью поточно-ориентированный и без блокировки

1 голос
/ 20 октября 2011

Первое решение является поточно-ориентированным, второе - нет. Однако вы можете использовать двойную проверку блокировки, чтобы уменьшить накладные расходы на получение блокировки

if (_similarity > bestSimilarity)  
{
    lock(locker) 
    {
         if (_similarity > bestSimilarity)
             bestSimilarity = _similarity;
    }
}
1 голос
/ 20 октября 2011

Второй поток не безопасен, другой поток может измениться _similarity после выполнения теста if.

...