C# lock 语句被阻塞。Ed 为您提供了正确的功能。只是不要忘记调用 Monitor.Exit()。您应该使用 try"/>

关于多线程:C#中是否有”尝试锁定,超时跳过”操作?

关于多线程:C#中是否有”尝试锁定,超时跳过”操作?

Is there a "try to lock, skip if timed out" operation in C#?

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

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!");
    }
}

推荐阅读