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?
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?
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.
在尝试审核我的代码以确保正确锁定时,我想知道同样的事情。我想出了一个使用第二个线程的方法。如果锁对调用线程可用,但对第二个线程不可用,则它必须由第一个线程持有。
/// <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"
}
我不会在生产代码中使用它 - 存在可能会爆发的竞争条件。但是,我的单元测试大多是单线程的,所以这很有用。
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.