严格来说,在多线程上使用委托可以安全地做什么?

时间:2012-03-27 08:58:10

标签: .net thread-safety

根据System.MulticastDelegate documentation

线程安全性

此类型的任何公共静态(Visual Basic中的Shared)成员都是线程安全的。不保证任何实例成员都是线程安全的。

System.Delegate的文档中存在相同的声明。

现在,代理人拥有一个不可变的API,但正如Eric Lippert解释"it is a fallacy to believe that just because a data structure does not admit any way for you change its contents, its implementation must be threadsafe!"

从现有委托创建新委托的一些机制是静态方法:Delegate.CombineDelegate.Remove。所以听起来这些都是线程安全的。给定多播代理A,B和C,我可以安全地将A和B组合在一个线程上制作D,同时将B和C组合在一起制作E。

但是调用委托不是静态方法。这是否意味着技术上我的代码可能会破坏,如果我在线程之间共享委托并在两者上调用它,或者如果我在一个线程上调用委托,而在另一个线程上将它与另一个线程组合?在这种情况下,符合标准的MulticastDelegate实现是否会导致未定义的行为? CombineRemove返回的代理是否保证不与任何其他代表共享任何隐藏的可变状态?

请注意,我在询问标准保证的内容,而不是C#编译器和CIL JIT编译器的当前行为。通过实验,我可以确定在我可用的体系结构中使用.NET和Mono中的每一个确实出现是安全的,但我看不出是什么指定或保证了这种行为。

2 个答案:

答案 0 :(得分:1)

委托有一个不可变的接口,但是在内部进行了变异。请参阅我的回答here以查看可能发生的事情的示例(答案与线程无关 - 它只是显示突变)。

严格来说您甚至不能保证能够同时调用委托。但由于现有代码的很大一部分,包括BCL本身依赖于此保证,因此可以安全地假设只读线程安全性

存在写入时的线程安全性不能轻易被认为是。我不知道这里的答案。该规范没有说明任何线程。可能无法更改委托的值,但可能会认为它们在线程的影响下发生了变化。谁知道。毕竟我们严格说话:)

答案 1 :(得分:0)

虽然我找不到任何实施限制,但我相信这是隐含的。

http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-334.pdf

中的第14.5.10.3节

“委托引用的方法和对象在委托实例化时确定,然后在委托的整个生命周期内保持不变。换句话说,不可能更改委托的目标方法或对象一旦创建了它。[注意:请记住,当两个代表合并或一个代表从另一个代表中删除时,会产生新的代理;没有现有的委托更改其内容。结束注释]“

虽然实施者可能故意制造这种行为不端,但我无法想象推动这种决定的因素。