我需要尝试锁定一个对象,如果它已经锁定,则继续(超时后或没有超时)。

C# 的 lock 语句是阻塞的。

有帮助吗?

解决方案

我相信你可以使用 Monitor.TryEnter().

lock 语句只是转换为 Monitor.Enter() 打电话和 try catch 堵塞。

其他提示

Ed 为您提供了合适的功能。只是别忘了打电话 Monitor.Exit(). 。你应该使用 try-finally 块以保证正确的清理。

if (Monitor.TryEnter(someObject))
{
    try
    {
        // use object
    }
    finally
    {
        Monitor.Exit(someObject);
    }
}

我遇到了同样的问题,我最终创建了一个类 TryLock 实现 IDisposable 然后使用 using 控制锁范围的语句:

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;
        }
    }
}

然后使用以下语法进行锁定:

var obj = new object();

using (var tryLock = new TryLock(obj))
{
    if (tryLock.HasLock)
    {
        Console.WriteLine("Lock acquired..");
    }
}

既然其他人已经为您指明了正确的方向,您可能会自己发现这一点,但 TryEnter 也可以采用超时参数。

如果您正在研究更复杂的内容,Jeff Richter 的“CLR Via C#”是一本关于 CLR 内部细节的优秀书籍。

考虑使用 AutoResetEvent 及其带有超时输入的方法 WaitOne。

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).aspxhttps://msdn.microsoft.com/en-us/library/cc190477(v=vs.110).aspx

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top