SwD*_*n81 6 c# extension-methods thread-safety
这个Extension方法线程安全吗?
public static class Extensions
{
public static void Raise<T>(this EventHandler<T> handler,
object sender, T args) where T : EventArgs
{
if (handler != null) handler(sender, args);
}
}
Run Code Online (Sandbox Code Playgroud)
或者我需要将其改为此吗?
public static class Extensions
{
public static void Raise<T>(this EventHandler<T> handler,
object sender, T args) where T : EventArgs
{
var h = handler;
if (h!= null) h(sender, args);
}
}
Run Code Online (Sandbox Code Playgroud)
你发现了一个有趣的环洞,它让每个人都绊倒了.不,它不是线程安全的.
虽然看起来像是通过方法参数复制了EventHandler <>引用,但这不是在运行时发生的事情.扩展方法需要内联,就像常规实例方法一样.事实上,由于它太小,因此极有可能被内联.没有副本,你必须自己制作一个.
这两个版本都不是线程安全的,这取决于你对"线程安全"的意思.考虑你的第二个版本:
var h = handler;
if (h!= null)
h(sender, args);
Run Code Online (Sandbox Code Playgroud)
"handler"是某个字段的副本,其中包含一个不可变委托.假设在null检查之后,该字段在另一个线程上变为"null".在这种情况下,您的代码不会崩溃,因为您已经复制了原始的非null值.但仅仅不崩溃并不会使程序线程安全.一个不会崩溃但仍会产生错误结果的程序仍然不是线程安全的.
假设当另一个线程将事件字段设置为null时,它还会改变某些状态,即先前的内容需要正确运行.您现在要运行一个事件处理程序,该处理程序依赖于在另一个线程上突变的状态; 你正在运行一个陈旧的事件处理程序.
没有简单的方法可以防止这个问题; 如果那是你所处的情况,那么你将不得不非常仔细地设计你的线程逻辑,以便处理这种情况.
| 归档时间: |
|
| 查看次数: |
2886 次 |
| 最近记录: |