【发布时间】:2010-02-18 23:13:46
【问题描述】:
我有对象,它们有锁。我想测试它们是否在没有获得锁的情况下被锁定。这个想法是如果我TryEnter() 然后我必须Exit() 如果true 只检查正确的锁。
这似乎是一个非常基本的问题,它是如何完成的?
【问题讨论】:
标签: c# multithreading locking exit
我有对象,它们有锁。我想测试它们是否在没有获得锁的情况下被锁定。这个想法是如果我TryEnter() 然后我必须Exit() 如果true 只检查正确的锁。
这似乎是一个非常基本的问题,它是如何完成的?
【问题讨论】:
标签: c# multithreading locking exit
当你看到锁被解锁后,你能得到什么信息?当您根据该信息做出决定时,锁定可能已经被占用。
【讨论】:
因为lock语句等价于:
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;
}
}
请注意,我将此函数命名为“ObjectWasUnlocked”,而不是“ObjectIsUnlocked”。不能保证当函数返回时它仍然会被解锁。
【讨论】:
在尝试审核我的代码以确保正确锁定时,我也想知道同样的事情。我想出了一个使用第二个线程的方法。如果锁对调用线程可用,但对第二个线程不可用,则它必须由第一个线程持有。
/// <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"
}
我不会在生产代码中使用它 - 存在可能会爆发的竞争条件。但是,我的单元测试大多是单线程的,所以这很有用。
【讨论】:
Monitor.Exit(lockObject)(在 finally 块中)。
【讨论】: