Вопрос об использовании Monitor.TryEnter и блокирующем объекте

Рассмотрим следующую функцию, которая реализует неблокирующий доступ только к одному потоку.

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, чтобы использовать ее как логический флаг, я начал получать это исключение.

13
задан abatishchev 25 August 2010 в 09:11
поделиться

2 ответа

Причина в том, что Все методы монитора принимают параметр System.Object . Когда вы передаете bool , требуется поле для преобразования в Object . Операция бокса создает новое значение System.Object для каждого вызова. Таким образом, методы TryEnter и Exit видят разные объекты и вызывают исключение.

Когда _locked был введен в объект , в коробке не было необходимости. Следовательно, методы TryEnter и Exit видят один и тот же объект и могут работать правильно.

Несколько других комментариев по поводу кода

  • TryEnter должен быть связан с Exit во всех случаях, и для здравого смысла вызов Exit должен быть в блоке finally. В противном случае вы предлагаете сценарий взаимоблокировки
  • Переменная _locked устанавливается только на false перед лицом исключения. Если выполнение не вызывает исключения, оно останется истинным, и ни один поток больше не войдет в блок if .
27
ответ дан 1 December 2019 в 19:58
поделиться

Установка времени ожидания на мониторе на 0 может помочь реализовать желаемое поведение. Используйте глобально объявленный объект для блокировки.

static object mylock = new object();

....

if (Monitor.TryEnter(mylock, 0))
{
    try
    {
           // Do work
    }
    finally
    {
        Monitor.Exit(mylock);
    }
}
5
ответ дан 1 December 2019 в 19:58
поделиться
Другие вопросы по тегам:

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