Tag: memory barriers

为什么标准C#事件调用模式是线程安全的,没有内存屏障或缓存失效? 类似的代码怎么样?

在C#中,这是以线程安全方式调用事件的标准代码: var handler = SomethingHappened; if(handler != null) handler(this, e); 其中,可能在另一个线程上,编译器生成的add方法使用Delegate.Combine创建一个新的多播委托实例,然后在编译器生成的字段上设置该实例(使用互锁比较交换)。 (注意:出于这个问题的目的,我们不关心在事件订阅者中运行的代码。假设它在删除时是线程安全且健壮的。) 在我自己的代码中,我想按照以下方式做类似的事情: var localFoo = this.memberFoo; if(localFoo != null) localFoo.Bar(localFoo.baz); 其中this.memberFoo可以由另一个线程设置。 (这只是一个线程,所以我不认为它需要联锁 – 但也许这里有副作用?) (而且,显然,假设Foo是“足够不可变的”,我们在这个线程上使用它时不会主动修改它。) 现在我理解这是线程安全的明显原因 :从引用字段读取是primefaces的。 复制到本地可确保我们不会获得两个不同的值。 ( 显然只能从.NET 2.0保证,但我认为它在任何理智的.NET实现中都是安全的吗?) 但我不明白的是:被引用的对象实例所占用的内存如何? 特别是在缓存一致性方面? 如果“writer”线程在一个CPU上执行此操作: thing.memberFoo = new Foo(1234); 什么保证分配新Foo的内存不会出现在“读取器”运行的CPU的缓存中,具有未初始化的值? 什么确保localFoo.baz (上面)不读取垃圾? (跨平台的保证有多好?在Mono上?在ARM上?) 如果新创建的foo恰好来自游泳池呢? thing.memberFoo = FooPool.Get().Reset(1234); 从内存的角度来看,这似乎没有什么不同,只是一个新的分配 – 但是.NET分配器可能会让第一个案例有效吗? 在我提出这个问题时,我的想法是,需要一个内存屏障来确保 – 不是因为读取依赖而无法移动内存访问 – 而是作为CPU清除任何缓存失效的信号。 […]

C#中的Volatile和Thread.MemoryBarrier

为了实现multithreading应用程序的无锁代码 ,我使用了volatile变量, 理论上 : volatile关键字用于确保所有线程都能看到volatile变量的最新值; 因此,如果线程A更新变量值,并且线程B在更新发生之后读取该变量,它将看到最近从线程A写入的最新值。正如我在Nutshell书中的C#4.0中读到的那样,这是不正确的,因为 应用volatile不会阻止写入后读取交换。 可以通过在每次获取volatile变量之前放置Thread.MemoryBarrier()来解决这个问题: private volatile bool _foo = false; private void A() { //… Thread.MemoryBarrier(); if (_foo) { //do somthing } } private void B() { //… _foo = true; //… } 如果这解决了问题; 考虑我们有一个while循环,它依赖于其中一个条件的值; 在while循环之前放置Thread.MemoryBarrier()是解决问题的正确方法吗? 例: private void A() { Thread.MemoryBarrier(); while (_someOtherConditions && _foo) { // do somthing. } […]

内存屏障vs内存对内存的影响缓存一致性时序

简化问题: 与内存屏障相比,由互锁操作引起的内存缓存一致性(或“刷新”)的时间是否存在差异? 让我们在C#中考虑 – 任何互锁操作与Thread.MemoryBarrier()。 我相信存在差异。 背景: 我读了很少关于内存障碍的信息 – 所有对预防特定类型的内存交互指令重新排序的影响,但是我找不到关于它们是否应该立即刷新读/写队列的一致信息。 我实际上发现很少有消息来源提到不保证操作的即时性(只保证特定的重新排序是有保证的)。 例如 维基百科 :“但是,要明确的是,这并不意味着任何操作都会在屏障完成时完成;只有完成操作的订购(当它们完成时)才能得到保证” Freebsd.org (障碍是硬件特定的,所以我猜一个特定的操作系统并不重要):“内存屏障只是确定内存操作的相对顺序;它们不保证内存操作的时间” 另一方面,Interlocked操作 – 从他们的定义 – 导致立即刷新所有内存缓冲区以保证更新的最新值更新导致内存子系统用值锁定整个缓存行,以防止从任何访问(包括读取)其他CPU /核心,直到操作完成。 我纠正还是错了? 免责声明: 这是我在这里的原始问题的演变。 在.NET中的可变新鲜度保证(易失性与易失性读取) EDIT1:修复了关于Interlocked操作的声明 – 内联文本。 编辑2:完全删除演示代码+它的讨论(因为一些人抱怨太多的信息)

锁定语句的内存障碍

我最近读到了关于内存障碍和重新排序的问题,现在我对它有些困惑。 请考虑以下情形: private object _object1 = null; private object _object2 = null; private bool _usingObject1 = false; private object MyObject { get { if (_usingObject1) { return _object1; } else { return _object2; } } set { if (_usingObject1) { _object1 = value; } else { _object2 = value; } } } private void Update() […]

内存屏障生成器

阅读Joseph Albahari的线程教程 ,以下内容被提及作为内存屏障的生成器: C#的lock语句( Monitor.Enter / Monitor.Exit ) Interlocked类的所有方法 使用线程池的异步回调 – 包括异步委托,APM回调和任务延续 设置和等待信令构造 任何依赖于信令的东西,例如启动或等待任务 此外,Hans Passant和Brian Gideon 补充了以下内容 (假设其中没有一个已经适合以前的类别之一): 启动或唤醒线程 上下文切换 Thread.Sleep() 我想知道这个清单是否完整(如果完整清单甚至可以实际制作) 编辑添加建议: 易失性(读数意味着获取围栏,写作意味着释放围栏)