【问题标题】:Locking on property without copying data锁定属性而不复制数据
【发布时间】:2014-10-28 14:54:08
【问题描述】:

我想访问可以被其他代码修改的属性,并确保对它的访问是线程安全的。当然,这个问题已经是asked and answered了。

但是,在我的特殊情况下,我有不同的具体问题。首先,多线程访问/修改场景,想必是很少见的情况,这种情况下我不会担心性能问题。此外,该属性本身非常大——它是一个浮动数组,大小可达 4096 x 4096,我想尽可能少地复制它。最后,我希望类接口易于使用——this solution 并非如此,因为它要求用户隐式锁定一个特殊的 SyncRoot。

是否有一种解决方案可以使我的属性线程安全,不需要额外的复制,并且允许客户端使用 getter(setter 是私有的)而无需记住锁定任何东西?

【问题讨论】:

  • 如果它很少更改,并且您使用的是 .NET 4.5,您可以使用 ReadOnlyCollection 并在 getter 中返回它。然后有一个单独的“SetUpdatedCollection”方法或类似方法,它会丢弃旧的 ReadOnlyCollection 并创建一个新的。在 getter 和 SetUpdatedCollection 方法中使用内部锁对象,并发将被强制执行。
  • 锯齿状数组是在其他线程上“调整大小”还是只修改了其内容?调整大小的情况要复杂得多,因为您不仅要担心同步访问数据,还要担心任何大小的缓存读取。
  • @user469104 由于我无法控制的原因 (Unity3d),我被锁定到 .NET 2.0

标签: c# properties thread-safety


【解决方案1】:

如果您希望易于使用,.NET 提供了内置的线程安全集合类来为您处理锁定。

http://msdn.microsoft.com/en-us/library/dd997305%28v=vs.110%29.aspx

你可以有一个

ConcurrentBag<float[]>

如果你自己动手,我会更担心未来的意外死锁而不是性能。当您开始在课堂外打开锁定时,死锁是一个非常现实的风险。

【讨论】:

    【解决方案2】:

    引用操作是atomic。因此,如果您确保使用 captured 实例并且集合本身是 不可变 (其元素不会以任何方式更改),则仅从集合中读取是线程安全的。

    ICollection<SomeType> SomeProperty { get; set; }
    
    // good
    var property = SomeProperty; // capture
    var a = property[1] + ...
    
    // not so good
    for(int i = 0; i < SomeProperty.Count; i++) // Count may be taken from new instance
    {
        var a = SomeProperty[i]; // really bad
        ...
    }
    
    // bad
    if(SomeProperty != null) ...
    

    如果要设置新集合,请先填充它,然后再设置。如果您只想更改一个元素 - 创建新集合,填充并设置。

    void AddItem(SomeType item)
    {
        var collection = new ICollection<SomeType>(SomeProperty); // copy old content
        collection.Add(item);
        SomeProperty = collection;
    }
    

    您也应该只有一位作家。不止一个需要至少某种同步:lock in AddItem()

    IDisposable 元素存在问题。但是这个想法(capturing+immutable)对于具有多个读取器和稀有写入器的场景中的简单类型应该很有效,因为不需要同步。

    【讨论】:

    • 这是关于收藏的绝佳答案。它也适用于数组吗?
    • 为什么会有任何不同?数组是更简单的结构。
    猜你喜欢
    • 2012-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-05
    相关资源
    最近更新 更多