Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/290.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#_.net_Multithreading_Concurrency_Clr - Fatal编程技术网

C# 锁定属性

C# 锁定属性,c#,.net,multithreading,concurrency,clr,C#,.net,Multithreading,Concurrency,Clr,我想知道在属性中如何正确使用锁。我正在编写一个多线程服务器应用程序,其中吞吐量非常重要。如果我有这样声明的财产: private DataPoint a; private object aLock = new object(); 最保守的锁似乎如下所示(称之为方法1)。但是,在这种情况下,在初始调用之后的每次调用中,都会有锁的开销: public DataPoint A { get { lock (aLoc

我想知道在属性中如何正确使用锁。我正在编写一个多线程服务器应用程序,其中吞吐量非常重要。如果我有这样声明的财产:

    private DataPoint a;
    private object aLock = new object();
最保守的锁似乎如下所示(称之为方法1)。但是,在这种情况下,在初始调用之后的每次调用中,都会有锁的开销:

    public DataPoint A
    {
        get
        {
            lock (aLock)
            {
                if (a == null)
                {
                    a = new DataPoint();
                }

                return a;
            }
        }
    }
或者,我应该将锁移到设置“a”的行(称之为方法2)。在这种情况下,可能会多次设置“a”(这是正常的),但一旦设置好,就不会有锁的开销

    public DataPoint A
    {
        get
        {
            if (a == null)
            {
                lock(aLock)
                {
                    a = new DataPoint();
                }
            }

            return a;
        }
    }
建议使用什么方法锁定对属性的并发访问?是方法1、方法2,还是以上都没有


谢谢。

在锁定示例中,您这样做是为了初始化一个值。假设null条件意味着需要初始化该值,则应在获取锁之前和之后检查该值:

if(a == null)
{
  lock(aLock)
  {
    if(a == null)
      a = new DataPoint();
  }
}

这是因为当一个线程在等待锁时,它在获得锁后要做的工作可能已经由另一个线程完成了。因此,当线程获得锁时,它应该检查工作是否仍然需要完成。

在锁定示例中,您这样做是为了初始化一个值。假设null条件意味着需要初始化该值,则应在获取锁之前和之后检查该值:

if(a == null)
{
  lock(aLock)
  {
    if(a == null)
      a = new DataPoint();
  }
}

这是因为当一个线程在等待锁时,它在获得锁后要做的工作可能已经由另一个线程完成了。因此,当线程获得锁时,它应该检查工作是否仍然需要完成。

在锁定之前应该检查null。 如果为null,则锁定,并再次检查null。 如果它仍然为空,则启动数据点并首先将其分配给临时变量。 完成后,将其分配给您的成员并返回

private DataPoint _dataPoint;

public DataPoint A
{
    get
    {
        if(_dataPoint != null)
            return _dataPoint;

        lock (aLock)
        {
            if (_dataPoint == null)
            {
                var dataPoint = new DataPoint();
                // do more stuff with dataPoint
                _dataPoint = dataPoint;
            }

            return _dataPoint;
        }
    }
}

您应该在锁定之前检查null。 如果为null,则锁定,并再次检查null。 如果它仍然为空,则启动数据点并首先将其分配给临时变量。 完成后,将其分配给您的成员并返回

private DataPoint _dataPoint;

public DataPoint A
{
    get
    {
        if(_dataPoint != null)
            return _dataPoint;

        lock (aLock)
        {
            if (_dataPoint == null)
            {
                var dataPoint = new DataPoint();
                // do more stuff with dataPoint
                _dataPoint = dataPoint;
            }

            return _dataPoint;
        }
    }
}

在.NET 4中,您有
System.Lazy
类型来处理这些问题:

class MyClass
{
    private readonly Lazy<DataPoint> lazy =
        new Lazy<Singleton>(() => new DataPoint());

    public DataPoint Instance { get { return lazy.Value; } }
} 
class-MyClass
{
私有只读懒惰=
新的延迟(()=>newdatapoint());
公共数据点实例{get{return lazy.Value;}}
} 

由于.NET 4中的

功能,您可以使用System.Lazy类型来解决以下问题:

class MyClass
{
    private readonly Lazy<DataPoint> lazy =
        new Lazy<Singleton>(() => new DataPoint());

    public DataPoint Instance { get { return lazy.Value; } }
} 
class-MyClass
{
私有只读懒惰=
新的延迟(()=>newdatapoint());
公共数据点实例{get{return lazy.Value;}}
} 


由于

的缘故,第二个示例中的
完全没有意义(没有双关语),但是您是否应该锁定(而不仅仅是有一个合理的初始化值)是另一个问题。为什么不在类构造函数中初始化数据点呢?第二个示例可能是一个有效的场景,取决于数据点的构造函数中发生了什么。我不应该使用“new DataPoint()”来进行说明,而是使用类似DataPoint.Create(“A”)…您正在开发一个服务器,您有锁吗?祝你好运。第二种情况确实有效。如果它已经初始化,您可能不想锁定它。但是,在锁(aLock)之后,您应该(再次)检查a是否为null,否则,如果在未初始化a时执行了对getter的两个并发调用,那么您可能会多次初始化。第二个示例中的
完全没有意义(没有双关语),但您是否应该锁定(与仅具有合理的初始化值相反)是另一个问题。为什么不在类构造函数中初始化数据点?第二个示例可能是有效的场景,具体取决于数据点构造函数中发生的情况。我不应该使用“new DataPoint()”出于说明目的,但使用了类似DataPoint.Create(“A”)…的内容。您正在开发一台服务器,并且有锁?祝您好运。第二种情况确实有效。如果已经初始化,您可能不希望锁定。但是,在锁(aLock)之后,您应该(再次)锁定如果A没有初始化,如果两个并发调用被调用,那么一些人会认为双检查锁定实际上是一个反模式,在ECMA CLI内存模型下,它甚至可能被破坏:(第三版本)在java内存模型下,除非引用是不稳定的,否则数据包是原子构造的——对于java来说,这意味着所有字段都是最终的。有些人认为双锁锁定实际上是反模式,在ECMA CLI内存模型下,它甚至可能被破坏:(第三版本)在Java内存模型下,除非引用是易失的或数据点是原子构造的,否则这肯定是不正确的。对于Java来说,这意味着所有字段都是最终字段。请注意,在这种特殊情况下,一个简单的静态只读字段将具有相同的效果。@Sebastian-何时以及如何初始化该字段?如Jon Skeet所述与第4项(或第5项)在同一条中指出,如果您提供静态构造函数,静态字段将在第一次类访问时初始化。@Sebastian我明白了。但是,由于您的注释,我已将post更改为更类似于OP的代码,现在没有任何内容是静态的……请注意,在这种特殊情况下,一个简单的静态只读字段将具有相同的效果。@Sebastian-何时以及如何您可以初始化该字段吗?正如Jon Skeet在与第4项(或第5项)相同的文章中指出的那样,如果您提供静态字段,静态字段将在一级访问上初始化