在以下文章中,Stephen向我们提供了如何使threadsafe事件发生的建议:
http://www.codeproject.com/Articles/37474/Threadsafe-Events.aspx
作者在解决方案2中解释了以下代码错误的原因:
MyEventHandler myEvent = this.MyEvent;
if (myEvent != null)
{
myEvent(this, args);
}事件委托的副本可能已过时.Stephen提供了以下解决该问题的解决方案。
为了确保读取非易失性字段的当前值,必须发出内存屏障或将复制操作包装在锁中(并且必须是事件添加/删除方法获得的相同锁),而不必进入痛苦的详细级别。
我对他没有解释的细节很感兴趣。从技术上讲,在这里使用内存屏障会发生什么?与上述方法有什么不同?
发布于 2014-07-15 21:47:20
您发布的代码的问题是,编译器/jitter/cpu可能会重新排序this.MyEvent字段的读取,并将其移回时间。换句话说,您可能会看到刚才读取的缓存值。
为了防止这种重新排序,您可以发出一个内存屏障(也称为全内存围栏),它告诉所有三个参与者不要在栅栏上方(或下方)移动任何指令。这将防止读取被缓存,或与其他先前的读取“合并”。
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认为事件是使用lock (this)实现的前提不再正确。事件现在是无锁的。您可以在这里看到由Chris:在C# 4的第一部分:锁中,事件得到了一点改进详细介绍的内容。
您也可能有兴趣阅读本系列的其他三个部分:
https://stackoverflow.com/questions/24768691
复制相似问题