Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 锁定非静态字段有什么问题?锁定特定实例的正确方法是什么?_C#_Multithreading_Locking_Thread Safety_Deadlock - Fatal编程技术网

C# 锁定非静态字段有什么问题?锁定特定实例的正确方法是什么?

C# 锁定非静态字段有什么问题?锁定特定实例的正确方法是什么?,c#,multithreading,locking,thread-safety,deadlock,C#,Multithreading,Locking,Thread Safety,Deadlock,为什么锁定非静态字段被认为是不好的做法 而且,如果我没有锁定非静态字段,那么如何在不锁定同一类或派生类的所有其他实例的情况下锁定实例方法 我写了一个例子让我的问题更清楚 public abstract class BaseClass { private readonly object NonStaticLockObject = new object(); private static readonly object StaticLockObject = new object()

为什么锁定非静态字段被认为是不好的做法

而且,如果我没有锁定非静态字段,那么如何在不锁定同一类或派生类的所有其他实例的情况下锁定实例方法

我写了一个例子让我的问题更清楚

public abstract class BaseClass
{

    private readonly object NonStaticLockObject = new object();
    private static readonly object StaticLockObject = new object();

    protected void DoThreadSafeAction<T>(Action<T> action)
        where T: BaseClass
    {
        var derived = this as T;
        if(derived == null)
        {
            throw new Exception();
        }
        lock(NonStaticLockObject)
        {
            action(derived);
        }
    }
}
public class DerivedClass :BaseClass
{
    private readonly Queue<object> _queue;
    public void Enqueue(object obj)
    {
        DoThreadSafeAction<DerivedClass>(x=>x._queue.Enqueue(obj));
    }
}
公共抽象类基类
{
私有只读对象NonStaticLockObject=新对象();
私有静态只读对象StaticLockObject=新对象();
受保护的void DoThreadSafeAction(操作操作)
其中T:BaseClass
{
var派生=此为T;
if(派生==null)
{
抛出新异常();
}
锁定(非静态锁定对象)
{
行动(衍生);
}
}
}
公共类派生类:基类
{
专用只读队列_队列;
公共无效排队(对象obj)
{
DoThreadSafeAction(x=>x.\u queue.Enqueue(obj));
}
}
如果我锁定了
StaticLockObject
,那么
DoThreadSafeAction
方法将锁定从
BaseClass
派生的所有类的所有实例,这不是我想要的。我想确保在对象的特定实例被锁定时,没有其他线程可以对其调用方法

更新


谢谢大家的帮助:我已经发布了另一个问题,作为你们提供的一些信息的后续。由于您似乎对这方面很精通,我发布了一个链接:

锁定实例字段也不错。有些人认为锁定实例本身是不好的,这是通过使用实例方法同步来实现的,但这是另一个故事。
如果其他类也使用实例进行锁定,那么实例上的锁定(或“this”)可能会产生副作用。您可以确定是否持有自己的个人锁。

您正在锁定用作锁的对象

不同之处在于锁所在的位置(或其可访问性)。
如果将其作为静态成员,则同一类的所有对象都可以访问它。所以你只需要一把锁,就可以把它们都锁上

如果您将它作为类的成员(非静态),那么它只能由该对象访问。因此,每个对象实例将获得一个锁

在这种情况下没有好的坏的做法。这只是一个你想实现什么的问题


只需记住避免将此锁定在对象中。

这不是因为它是一种不好的做法,而是因为你的目的是什么

静态字段可访问(或“通用于”)该类型的所有实例。因此,锁定这样一个静态字段使您能够控制该类型的所有实例之间的并发,或者,实现的并发控制范围是该类型的所有实例。

但是,如果锁定非静态字段,则锁定将仅对该实例有效,因此您只能在该实例内控制并发,或者,实现的并发控制范围是该实例。


现在,无论何时锁定一个对象,我都会这样做。我同意的资源是什么?可能是数据库,可能是一堆实例字段,在我进行特定处理时无法更改,等等。一旦我知道我将自己锁定在什么范围之外,我会检查它的范围

  • 如果它是我的应用程序之外的实体,那么它就是应用程序范围。所有东西都必须同时上锁
  • 如果它是一堆实例字段,那么它就是实例范围
  • 如果它是一组静态字段,那么它就是类型范围
  • 因此,对于1和3,使用静态字段。对于2,使用实例字段

    现在,另一件事:通常,对于1,您将有一个围绕该资源的类。通常,您会将该类设计为一个。现在,对于单例,这很有趣:通过设计,您可以保证只有一个实例,所以无论您锁定的是实例还是静态字段


    注:如果您使用锁来保护singleton的实例化,那么它当然应该是静态的。(为什么?

    谁说锁定实例字段是不好的做法?