9

I have objects, they get locks. I want to test if they are locked without acquiring a lock. The idea is if I TryEnter() then i have to Exit() if true to only check the lock correctly.

Seems like a really basic question, how is it done?

4

4 回答 4

22

What possible information can you get from knowing the lock was unlocked back when you looked at it? By the time you make a decision based on that information, the lock may be already taken.

于 2010-02-18T23:18:01.420 回答
3

在尝试审核我的代码以确保正确锁定时,我想知道同样的事情。我想出了一个使用第二个线程的方法。如果锁对调用线程可用,但对第二个线程不可用,则它必须由第一个线程持有。

    /// <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"
}

我不会在生产代码中使用它 - 存在可能会爆发的竞争条件。但是,我的单元测试大多是单线程的,所以这很有用。

于 2010-12-07T23:22:21.973 回答
3

Because the lock statement is equivalent to:

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

Can you just do this?

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

Note that I'm naming this function "ObjectWasUnlocked" as opposed to "ObjectIsUnlocked". There is no guarantee that it will still be unlocked when the function has returned.

于 2010-02-18T23:26:47.797 回答
1

这是一个相关的问题

检查当前线程是否拥有锁

结论是“你不能”

于 2010-10-21T08:35:21.670 回答