Threadsafe使用内存屏障的事件

时间:2014-07-15 21:41:03

标签: c# .net events

在下面的文章中,Stephen Cleary向我们提供了有关如何制作线程安全事件的建议:

http://www.codeproject.com/Articles/37474/Threadsafe-Events.aspx

作者在解决方案#2中解释了为什么以下代码出错:

MyEventHandler myEvent = this.MyEvent;
if (myEvent != null)
{
    myEvent(this, args);
}

活动代表的副本可能已过时。斯蒂芬为这个问题提供了以下解决方案。

  

没有陷入痛苦的细节,为了确保这一点   一个人必须读取非易失性字段的当前值   发出内存屏障或将复制操作包装在锁中   (并且它必须与事件添加/删除获取的锁相同   方法)。

我对细节很感兴趣,但遗憾的是他并没有解释。在这里使用内存屏障时技术上会发生什么?与上述方法有什么不同?

1 个答案:

答案 0 :(得分:1)

您发布的代码的问题是编译器/ jitter / cpu可能会重新排序this.MyEvent字段的读取,并且会及时移回。换句话说,您可能会看到之前读过的缓存值。

为了防止这种重新排序,你发出一个内存屏障(又名完整的内存栅栏),告诉所有3个参与者不要在栅栏上方(或下方)移动任何指令。这将阻止读取被缓存,或者被“合并”#34;与其他早期的读物。

Thread.MemoryBarrier();

//--> no instructions can be moved above or below the fence <--

MyEventHandler myEvent = this.MyEvent;
if (myEvent != null)
{
    myEvent(this, args);
}

另外,请注意该博客帖子上的日期,它已经很老了。 从那时起,C#4.0的发布就重新编写了事件。

Stephen Cleary的前提是使用lock (this)实现事件已不再适用。事件现在是无锁的。你可以在这里看到Chris Burrows详细介绍的内容:Events get a little overhaul in C# 4, Part I: Locks

您可能也有兴趣阅读本系列的其他3个部分: