Действительно ли это - корректный Взаимно блокируемый дизайн синхронизации?

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

public class Sample
{
    private static Sample _lastSample;
    private static int _isSampling;

    public static Sample TakeSample(AutomationManager automation)
    {
        //Only start sampling if not already sampling in some other context
        if (Interlocked.CompareExchange(ref _isSampling, 0, 1) == 0)
        {
            try
            {
                Sample sample = new Sample();
                sample.PerformSampling(automation);
                _lastSample = sample;
            }
            finally
            {
                //We're done sampling
                _isSampling = 0;
            }
        }

        return _lastSample;
    }

    private void PerformSampling(AutomationManager automation)
    {
        //Lots of stuff going on that shouldn't be run in more than one context at the same time
    }
}

Действительно ли это безопасно для использования в сценарии, который я описал?

5
задан Dan Bryant 7 April 2010 в 21:23
поделиться

2 ответа

Да, это выглядит безопасным, потому что int является атомарный тип здесь. Но я бы все же посоветовал заменить

private static int _isSampling;

на

private static object _samplingLock = new object();

и использовать:

lock(_samplingLock)
{
    Sample sample = new Sample();
    sample.PerformSampling(automation);
   _lastSample = sample;
}

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

NB: Я ожидал сопоставимой скорости, блокировка использует управляемый класс Monitor, который внутренне использует Interlocked.

Редактировать:

Я пропустил аспект отсрочки, вот другая версия:

   if (System.Threading.Monitor.TryEnter(_samplingLock))
   {
     try
     {
         .... // sample stuff
     }
     finally
     {
          System.Threading.Monitor.Exit(_samplingLock);
     }
   }
5
ответ дан 15 December 2019 в 00:55
поделиться

Обычно я объявляю volatile bool и делаю что-то вроде:

private volatile bool _isBusy;
private static Sample _lastSample;

private Sample DoSomething()
{
     lock(_lastSample)
     {
       if(_isBusy)
          return _lastSample;
       _isBusy = true;
     }

     try
     {
       _lastSample = new sameple//do something
     }
     finally
     {
        lock(_lastSample)
        {
           _isBusy = false;
        }
     }
     return _lastSample;
} 
-1
ответ дан 15 December 2019 в 00:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: