c#中线程安全的锁定方法和方法调用?

Locking method and calls of method for thread-safety in c#?

我是否应该为线程锁定在 c# 中调用线程安全方法的代码的一部分?

例如:

T Eject (bool? state)
    {
        lock (this)
        {
            //somecode
            return _objects[i];
        }
    }

    public T TakeNew()
    {
        return Eject(null);
    }

    public T Reserve()
    {
        return Eject(true);
    }

或者我应该像这样锁定 return:

lock(this)
    {       
        return Eject(true);
    }

如果我锁定所有 Eject(true) 调用,我是否需要锁定方法 Eject 块?我认为,如果我锁定方法和方法调用,它会造成线程死锁。在这种情况下,创建线程安全代码的更好方法是什么?

感谢您的回答!

最佳做法是只锁定尽可能少的代码,因为这样可以最大限度地减少锁争用的机会(从而提高性能和可伸缩性),还可以提高代码的可读性(更容易看出哪些对象受锁保护) .

在您的情况下,仅在 Eject 方法中锁定对 _objects 的访问就足够了(请参阅下面的代码)。锁定方法调用 return Eject(true) 就没有必要了(但如果你这样做,它不会导致死锁)。

另外,使用 this 进行锁定也被认为是错误的做法,因为在某些情况下这会导致死锁。因此专用对象通常存储在封闭的私有或受保护字段中 class 并用于锁定(再次参见下面的代码)。

所以这应该没问题:

class Foo<T>
{
    // Dedicated object instance used for locking
    private Object m_MyLock = new Object();

    T Eject(bool? state)
    {
        lock (m_MyLock)//You typically use the same locking object everywhere within the class
        {
            //somecode
            return _objects[i];
        }
    }

    string SomeOtherMethod()//Some other method that needs to be threadsafe too
    {
        lock (m_MyLock)//You typically use the same locking object everywhere within the class
        {
            return _objects[i].ToString();
        }
    }

    public T TakeNew()
    {
        return Eject(null);
    }

    public T Reserve()
    {
        return Eject(true);
    }
}

编辑:

澄清 OP 的评论:您不应为每个锁创建新的锁定对象。您通常在 class 中使用相同的锁定对象。当您在 class 中使用 lock(this) 而代码的另一部分 不知道它 时,我正在谈论的死锁情况可能会发生(例如第三方库代码)以这种不幸的方式使用 class 的实例作为锁定对象,导致死锁。这种情况在 Why is lock(this) {…} bad? 中有更好的解释(包括这种情况的示例)。这就是为什么你应该使用你的私有对象(m_MyLock)进行锁定,因为这样就不会发生这种情况(尽管它不排除其他可能的死锁情况)。