#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
использоваться чем-то другим, пока ваш цикл занят другими делами.