Рассмотрим следующую функцию, которая реализует неблокирующий доступ только к одному потоку.
public bool TryCancelGroup()
{
if (Monitor.TryEnter(_locked))
{
if (_locked == false)
{
_locked = true;
try
{
// do something
}
catch (Exception ex)
{
_locked = false;
}
finally
{
Monitor.Exit(_locked);
}
}
return _locked;
}
else
{
return false;
}
}
А вот как _locked
переменная определена.
bool _locked = false;
Теперь, когда программа достигает Monitor.Exit (_locked);
она выдает System.Threading.SynchronizationLockException
о том, что переменная _locked ранее не была синхронизирована ,
Раньше все работало, когда переменная _locked была определена как объект.
object _locked = new object();
Когда я изменил ее на bool, чтобы использовать ее как логический флаг, я начал получать это исключение.
Причина в том, что Все методы монитора
принимают параметр System.Object
. Когда вы передаете bool
, требуется поле для преобразования в Object
. Операция бокса создает новое значение System.Object
для каждого вызова. Таким образом, методы TryEnter
и Exit
видят разные объекты и вызывают исключение.
Когда _locked
был введен в объект
, в коробке не было необходимости. Следовательно, методы TryEnter
и Exit
видят один и тот же объект и могут работать правильно.
Несколько других комментариев по поводу кода
_locked
устанавливается только на false
перед лицом исключения. Если выполнение не вызывает исключения, оно останется истинным, и ни один поток больше не войдет в блок if
. Установка времени ожидания на мониторе на 0 может помочь реализовать желаемое поведение. Используйте глобально объявленный объект для блокировки.
static object mylock = new object();
....
if (Monitor.TryEnter(mylock, 0))
{
try
{
// Do work
}
finally
{
Monitor.Exit(mylock);
}
}