использование вложенного / внешнего замка c#

#c# #.net #syntax #locking

#c# #.net #синтаксис #блокировка

Вопрос:

Нормально ли писать такой код:

 lock(syncObject) {
    try {

        do {
            // do some computations

            if(this.isStopped) break;
            Thread.Sleep(30000);

        } while(true);
    } 
    catch(Exception ex) {
        Logger.Log.Warn(ex);
    }
}
  

или было бы лучше поместить эту часть внутри while цикла:

 // ...
do {
    // do some computations

    lock(syncObject) {
        if(this.isStopped) break;
    }
    Thread.Sleep(30000);

} while(true);
// ...
  

Комментарии:

1. что такое isStopped ? if(this.isStopped) предполагает bool ; lock(isStopped) предполагает объект… также: что будет изменять значение this.isStopped ?

2. Извините, упустил это из виду…

3. Какова цель кода? Можно написать код, если он достигает желаемой цели, но вы не объясняете, в чем заключается эта цель.

4. Требование к блокировке не видно из вопроса. Высока вероятность того, что все это неправильно, тестирование условия «остановить поток» должно выполняться EventWaitHandle. WaitOne(0) или BackgroundWorker. Отмена отправки или CancellationToken. IsCancellationRequested

5. Мне предложили не использовать такие вещи, как autoResetEventInstance.WaitOne(0) из-за возможности бесконечного ожидания.

Ответ №1:

преимущество наличия lock внутри цикла заключается в том, что это означает, что другой поток может получить lock с целью изменения значения. Однако этого также можно достичь с помощью Monitor.Wait / Monitor.PulseAll , что означало бы, что вам не нужно ждать полных 30 секунд при выходе. Например:

 lock(syncLock) {
    try {    
        do {
            // do some computations
            if(this.isStopped) break;
            Monitor.Wait(syncLock, 30000);
        } while(true);
    } 
    catch(Exception ex) {
        Logger.Log.Warn(ex);
    }
}
  

и для ее освобождения:

 lock(syncLock) {
    this.isStopped = true;
    Monitor.PulseAll(syncLock);
}
  

Комментарии:

1. Значение isStopped флага изменяется внешним вызовом из диспетчера служб. Это выдержка из службы Windows.

2. @lexeme проблема в том, что поля не гарантированно будут перечитаны, если вы измените значение в другом потоке…

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

4. @lexeme Я имею в виду, что с первой версией в вашем вопросе есть вероятность, что isStopped будет кэшировано, и оно никогда больше не будет проверять фактическое поле; обработка потоков сложна…

5. Почему lock внутри цикла доступно другим потокам?

Ответ №2:

В вашем первом примере, если вы запретите запуск любого другого кода, который использует syncObject .

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