我需要尝试锁定一个对象,如果它已经锁定就继续(在超时之后,或者没有它)。
C# lock 语句被阻塞。
Ed 为您提供了正确的功能。只是不要忘记调用 Monitor.Exit()。您应该使用 try-finally 块来保证正确清理。
1 2 3 4 5 6 7 8 9 10 11
| if (Monitor.TryEnter(someObject))
{
try
{
// use object
}
finally
{
Monitor.Exit(someObject);
}
} |
我相信你可以使用Monitor.TryEnter()。
lock 语句只是转换为一个 Monitor.Enter() 调用和一个 try catch 块。
我遇到了同样的问题,我最终创建了一个实现 IDisposable 的类 TryLock,然后使用 using 语句来控制锁的范围:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class TryLock : IDisposable
{
private object locked;
public bool HasLock { get; private set; }
public TryLock(object obj)
{
if (Monitor.TryEnter(obj))
{
HasLock = true;
locked = obj;
}
}
public void Dispose()
{
if (HasLock)
{
Monitor.Exit(locked);
locked = null;
HasLock = false;
}
}
} |
然后使用下面的语法来锁定:
1 2 3 4 5 6 7 8 9
| var obj = new object();
using (var tryLock = new TryLock(obj))
{
if (tryLock.HasLock)
{
Console.WriteLine("Lock acquired..");
}
} |
考虑使用带有超时输入的 AutoResetEvent 及其方法 WaitOne。
1 2 3 4 5 6 7 8 9 10 11 12 13
| static AutoResetEvent autoEvent = new AutoResetEvent(true);
if(autoEvent.WaitOne(0))
{
//start critical section
Console.WriteLine("no other thread here, do your job");
Thread.Sleep(5000);
//end critical section
autoEvent.Set();
}
else
{
Console.WriteLine("A thread working already at this time.");
} |
请参阅 https://msdn.microsoft.com/en-us/library/cc189907(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/system.threading.autoresetevent(v=vs.110).aspx 和 https://msdn.microsoft.com/en-us/library/cc190477(v =vs.110).aspx
既然其他人已经为您指出了正确的方向,您可能会自己发现这一点,但 TryEnter 也可以采用超时参数。
Jeff Richter 的"CLR Via C#"是一本关于 CLR 内部细节的优秀书籍,如果您正在研究更复杂的内容。
基于Dereks的回答小帮手方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| private bool TryExecuteLocked(object lockObject, Action action)
{
if (!Monitor.TryEnter(lockObject))
return false;
try
{
action();
}
finally
{
Monitor.Exit(lockObject);
}
return true;
} |
用法:
1 2 3 4 5 6 7 8
| private object _myLockObject;
private void Usage()
{
if (TryExecuteLocked(_myLockObject, ()= DoCoolStuff()))
{
Console.WriteLine("Hurray!");
}
} |