Проверить блокировку без ее приобретения? - PullRequest
9 голосов
/ 19 февраля 2010

У меня есть предметы, они получают замки. Я хочу проверить, заблокированы ли они, не получая блокировки. Идея в том, что если я TryEnter(), тогда мне нужно Exit(), если true, чтобы только правильно проверить блокировку.

Похоже на действительно простой вопрос, как это делается?

Ответы [ 4 ]

22 голосов
/ 19 февраля 2010

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

3 голосов
/ 08 декабря 2010

Мне было интересно то же самое, когда я пытался проверить мой код на предмет правильной блокировки. Я придумал метод, используя второй поток. Если блокировка доступна вызывающему потоку, но недоступна второму потоку, она должна удерживаться первым.

    /// <summary>
/// Utiltity for checking if a lock has already been acquired.
/// WARNING: This test isn't actually thread-safe, 
/// it's only really useful for unit tests
/// </summary>
private static bool ObjectIsAlreadyLockedByThisThread(object lockObject)
{
    if (!Monitor.TryEnter(lockObject))
    {
        // another thread has the lock
        return false;
    }

    Monitor.Exit(lockObject);

    bool? LockAvailable = null;

    var T = new Thread(() =>
    {
        if (Monitor.TryEnter(lockObject))
        {
            LockAvailable = true;
            Monitor.Exit(lockObject);
        }
        else
        {
            LockAvailable = false;
        }
    });

    T.Start();

    T.Join();

    return !LockAvailable.Value;
}

// Tests:
public static void TestLockedByThisThread()
{
    object MyLock = new object();
    lock (MyLock)
    {
        bool WasLocked = ObjectIsAlreadyLockedByThisThread(MyLock);

        Debug.WriteLine(WasLocked); // prints "True"
    }
}

public static void TestLockedByOtherThread()
{
    object MyLock = new object();

    var T = new Thread(() =>
    {
        lock (MyLock)
        {
            Thread.Sleep(TimeSpan.FromSeconds(2));
        }
    });

    T.Start();
    Thread.Sleep(TimeSpan.FromSeconds(1));

    bool WasLocked = ObjectIsAlreadyLockedByThisThread(MyLock);

    T.Join();

    Debug.WriteLine(WasLocked); // prints "False"
}

public static void TestNotLocked()
{
    object MyLock = new object();

    bool WasLocked = ObjectIsAlreadyLockedByThisThread(MyLock);

    Debug.WriteLine(WasLocked); // prints "False"
}

Я бы не стал использовать это в рабочем коде - есть условие гонки, которое может взорваться. Однако мои модульные тесты в основном однопоточные, так что это было полезно.

3 голосов
/ 19 февраля 2010

Поскольку оператор блокировки эквивалентен:

System.Threading.Monitor.Enter(x);
try {
   ...
}
finally {
   System.Threading.Monitor.Exit(x);
}

Вы можете просто сделать это?

bool ObjectWasUnlocked(object x)
{
   if(System.Threading.Monitor.TryEnter(x))
   {
       System.Threading.Monitor.Exit(x);
       return true;
   }
   else
   {
       return false;
   }
}

Заметьте, что я называю эту функцию "Объект Был Разблокировано ", в отличие от" ObjectIsUnlocked ".Нет гарантии, что он все еще будет разблокирован после возврата функции.

1 голос
/ 21 октября 2010

Вот связанный с этим вопрос

Проверка, имеет ли текущий поток блокировку

Вывод: «Вы не можете»

...