ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

在C#中装箱/取消装箱结构可以产生与原子相同的效果吗?

2019-06-09 05:53:27  阅读:258  来源: 互联网

标签:c multithreading boxing


根据C#规范,是否有任何保证foo.Bar具有相同的原子效果(即读取foo.来自不同线程的棒在被不同线程写入时永远不会看到部分更新的结构)?

我一直认为它确实如此.如果确实如此,我想知道规范是否保证它.

    public class Foo<T> where T : struct
    {
        private object bar;

        public T Bar
        {
            get { return (T) bar; }
            set { bar = value; }
        }
    }

    // var foo = new Foo<Baz>();

编辑:@vesan这不是Atomic Assignment of Reference Sized Structs的副本.这个问题要求装箱和拆箱的效果,而另一个是关于结构中的单个引用类型(不涉及装箱/拆箱).这两个问题之间唯一的相似之处是结构和原子(你真的读过这个问题吗?).

EDIT2:这是基于Raymond Chen答案的原子版:

public class Atomic<T> where T : struct
{
    private object m_Value = default(T);

    public T Value
    {
        get { return (T) m_Value; }
        set { Thread.VolatileWrite(ref m_Value, value); }
    }
}

解决方法:

不,结果不是原子的.虽然对引用的更新确实是原子的,但它不是同步的.可以在装箱对象内的数据变为可见之前更新引用.

让我们把事情分开.盒装类型T基本上是这样的:

class BoxedT
{
    T t;
    public BoxedT(T value) { t = value; }
    public static implicit operator T(BoxedT boxed) { return boxed.t; }
}

(不完全,但足够接近本讨论的目的.)

当你写作

bar = value;

这是简写

bar = new BoxedT(value);

好的,现在让我们把这个任务分开.涉及多个步骤.

>为BoxedT分配内存.
>使用值的副本初始化BoxedT.t成员.
>保存对BoxedT的引用.

步骤3的原子性意味着当您从条形图中读取时,您将获得旧值或新值,而不是两者的混合.但它不能保证同步.特别地,在操作2之前,操作3可以对其他处理器可见.

假设bar的更新对另一个处理器可见,但BoxedT.t的初始化不是.当该处理器尝试通过读取Boxed.t值来取消装箱BoxedT时,不能保证读取在步骤2中写入的t的完整值.它可能只获得值的一部分,而另一部分包含默认值( T).

这与双重检查锁定模式基本相同,但更糟糕的是因为你根本没有锁定!解决方案是使用发布语义更新bar,以便在更新bar之前将所有先前的存储提交到内存.根据C#4语言规范10.5.3节,这可以通过将bar标记为volatile来完成. (这也意味着来自bar的所有读取都将具有获取语义,这可能是您想要的,也可能不是.)

标签:c,multithreading,boxing
来源: https://codeday.me/bug/20190609/1203074.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有