Подтвердить что ты не робот

С# Как обнаружить объект уже заблокирован

Как определить, заблокирован ли объект или нет?

Monitor.TryEnter (как описано в Есть ли способ определить, заблокирован ли объект?) не работает для меня, потому что он блокирует объект, если он не заблокирован.

Я только хочу проверить, заблокирован ли он и где-то еще в моем коде. Я буду использовать класс Monitor для блокировки объекта.

Я знаю, что можно использовать, например, логическое поле (например, private bool ObjectIsLocked), но что его обнаружить с помощью самого объекта блокировки.

Пример кода ниже показывает, что я хочу сделать:

private static object myLockObject = new object();

private void SampleMethod()
{
    if(myLockObject /*is not locked*/) // First check without locking it
    {
        ...
        // The object will be locked some later in the code
        if(!Monitor.TryEnter(myLockObject)) return;

        try
        {

            ....
        }
        catch(){...}
        finally
        {
            Monitor.Exit(myLockObject);
        }
    }
}
4b9b3361

Ответ 1

Вы ошибаетесь.. Если у вас нет блокировки объекта, вы не можете проверить, заблокирована ли она (и если у вас есть блокировка, вы будете знать заранее). Вы можете "спросить", "заблокирован"? и получить "не" в качестве ответа, то в следующий наносекунду другой поток может взять блокировку, и ваша программа войдет в поврежденное состояние. Это просто не путь к многопоточным приложениям и причина, почему .NET не имеет метода Monitor.IsLocked. Если ваш код должен проверить блокировку, прежде чем приобретать ее, чтобы у вас возникла проблема с дизайном. Попытка решить проблему с незащищенными флагами - это плохое решение, гарантированное 100% шансом, что это не сработает.

Во всяком случае, не используйте bool var для сигнализации о том, что состояние многопоточности заблокировано (потому что вы можете иметь такую ​​же проблему, вы читаете "ложь" и 1 наносекунду позже, а другой поток будет писать "true" ). Используйте Interlock.CompareExchange.

private static _lockFlag = 0; // 0 - free

if (Interlocked.CompareExchange(ref _lockFlag, 1, 0) == 0){
   // only 1 thread will enter here without locking the object/put the
   // other threads to sleep.

   Monitor.Enter(yourLockObject); 

   // free the lock.
   Interlocked.Decrement(ref _lockFlag);
}

Вы увидите, что вам нужно будет изменить _lockFlag во всех местах, где можно было бы заблокировать ваш объект. Другими словами, вы создадите пользовательскую систему блокировки вокруг собственной.

Ответ 2

Monitor.IsEntered должен сделать трюк.

Изменить: я просто перечитаю документацию, и он говорит:

Определяет, поддерживает ли текущий поток блокировку указанного объект.

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

Ответ 3

Нет способа сделать это с помощью класса Monitor в С#

Просто используйте

    var lockedBySomeoneElse = !Monitor.TryEnter(obj);
    if (!lockedBySomeoneElse) Monitor.Exit(obj);
    // the variable 'lockedBySomeoneElse' has the info you want

Другие блокировки, такие как readerwriterlockslim, действительно не помогают. Это может сказать вам, как могут быть читатели, но нет, если писатель занят, - (

также, если вы используете собственное предложение "private bool ObjectIsLocked", которое я бы выбрал, я думаю, вы должны использовать

      private volatile bool ObjectIsLocked

Это приведет к тому, что С# лучше изменит его с помощью многопоточных обновлений.

Ответ 4

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

Ответ 5

В принципе, вы можете проверить поле индекса объекта Sync Block, которое имеет индекс связанной лениво распределенной структуры в массиве Sync Blocks - каждый объект имеет это поле, и каждый объект, используемый для синхронизации, имеет это поле. Эти структуры используются для координации синхронизации потоков. Тем не менее, я очень сомневаюсь, что вы сможете получить доступ к этой информации без Profiling API.