使自定义对象线程安全

时间:2015-06-09 14:22:15

标签: c# .net multithreading

我发布了关于返回集合的earlier question,并且出现了线程安全主题。我得到了这个link来做更多的阅读,我找到了这个特殊的界限:

  

一般情况下,避免锁定公共类型或超出您的实例   代码的控制。

首先,如果我错了,请纠正我,但微软是否锁定公共类型,即余额变量?

其次,我将如何锁定自己的getter / setter属性。假设我有以下课程:

private int ID;

public Person(int id)
{
    this.Identification= id;

}

public int Identification
{
    get { return this.ID; }

    private set
    {
        if (value == 0)
        {
            throw new ArgumentNullException("Must Include ID#");
        }
        this.ID = value;
    }
}

吸气剂公开正确吗?只有setter被声明为private。那么,我如何锁定,或使我的getter / setter属性线程安全?

3 个答案:

答案 0 :(得分:4)

您应该在CKEDITOR.instances['cm_ckeditor'].getData()类中定义一个变量,如此

Person

如果您要对private readonly object _lock_ = new Object(); 的所有实例进行同步,则应将其设为Person

然后当你想要锁定时,你可以这样做

static

我建议你阅读这些文章。 12

答案 1 :(得分:1)

当您需要锁定变量时,您需要锁定使用该变量的每个位置。锁不是变量 - 它是用于使用变量的代码区域。

如果您只是在一个地方阅读,那么无关紧要 - 如果您需要锁定变量,则需要无处不在使用该变量。

lock的替代是Interlocked类 - 它使用处理器级原语进行锁定,速度更快一些。 Interlocked但是无法保护多个语句(并且有两个Interlocked个数字与在单个lock中包含这两个语句不同。)

锁定时,必须锁定引用类型的实例(在大多数情况下(但不总是),它也应该是静态实例)。这是为了确保所有锁实际上都在相同的实例上取出,而不是它的副本。显然,如果您在不同的地方使用副本,则不会锁定相同的内容,因此您的代码将无法正确序列化。

例如:

private static readonly object m_oLock = new object ();

...

lock ( m_oLock )
{
    ...
}

使用非静态锁是否安全需要对代码进行详细分析 - 在某些情况下,它会导致更多的并行性,因为相同的代码区域被锁定较少但是对它的分析可能非常棘手 - 如果你不确定,只需使用static锁定对象。采用开放锁定的成本很小,但不正确的分析可能会导致需要花费很长时间才能进行调试的错误。

修改

这是一个显示如何锁定属性访问的示例:

private int ID; // do NOT lock on value type instances
private static readonly object Lock = new object ();

public Person(int id)
{
    this.Identification = id;
}

public int Identification
{
    get
    { 
        lock ( Lock )
        {
            return this.ID;
        }
    }

    private set
    {
        if (value == 0)
            throw new ArgumentNullException("Must Include ID#");

        lock ( Lock )
        {
            this.ID = value;
        }
    }
}

由于您的属性只执行简单的get / set操作,因此您可以尝试使用Interlocked.CompareExchange而不是完全锁定 - 它会使事情稍微快一些。但请记住,互锁操作与锁定不同。

编辑2:

还有一件事:int上的一个简单的获取/设置不需要锁定 - 读取和写入32位值(本身)本身就是原子的。所以这个例子太简单了 - 只要你不尝试在应该以原子方式完成的多个操作中使用ID,就不需要锁定。但是,如果您的实际代码在检查和设置ID时实际上更复杂,则可能需要锁定并且您需要锁定组成原子操作的所有操作。这意味着您可能必须从getter / setter中取出锁定 - 变量的get / set对上的2个锁定与它们周围的单个锁定不同。

答案 2 :(得分:1)

关于Microsoft文章的第一个问题的答案: 不。该文章没有锁定balance变量。它锁定私有thisLock变量。所以这个例子很好。

其次,根据您发布的代码,您不需要添加任何锁定来使您的类线程安全,因为您的数据是不可变的。创建Person的实例并在构造函数中设置Identification属性的值后,您的类设计不允许该属性再次更改。这是不变的,而这本身就提供了线程安全性。所以你不需要费心添加锁等。再次,假设您的代码示例是准确的。

编辑: 这个link可能对您有用。