Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/294.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#代理是否线程安全?_C#_Multithreading_Delegates_Thread Safety - Fatal编程技术网

C#代理是否线程安全?

C#代理是否线程安全?,c#,multithreading,delegates,thread-safety,C#,Multithreading,Delegates,Thread Safety,如果您有一个具有委托成员变量的类实例,并且多个线程调用该委托(假设它指向一个长期运行的方法),那么是否存在争用问题 由于每个线程都有自己的调用堆栈,您是否需要锁定委托,或者每个线程调用委托所指向的方法是否安全?不,它们不是线程安全的,是的,您必须自己管理并发性。直接来自以下文档: 此类型的任何公共静态(在Visual Basic中共享)成员都是线程安全的。任何实例成员都不能保证线程安全 该类包含相同的信息,因此您可以使用它。修改事件不是线程安全的,但调用委托是安全的。 因为委托是不可变的,所以它

如果您有一个具有委托成员变量的类实例,并且多个线程调用该委托(假设它指向一个长期运行的方法),那么是否存在争用问题


由于每个线程都有自己的调用堆栈,您是否需要锁定委托,或者每个线程调用委托所指向的方法是否安全?

不,它们不是线程安全的,是的,您必须自己管理并发性。

直接来自以下文档:


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


该类包含相同的信息,因此您可以使用它。

修改事件不是线程安全的,但调用委托是安全的。 因为委托是不可变的,所以它是线程安全的。见此处备注:

借用自: 在CLR Via C#Richter中,他指出了关于多线程类中事件调用的几个微妙之处:

委托链是不可变的;将创建一个新链来替换第一个链。 订阅服务器为零的委托链为空。
这意味着(如果您的事件是公共的),它可以随时从null转换为非null,反之亦然。

关于委托的调用,答案是肯定的。

调用委托是线程安全的,因为委托是不可变的。但是,必须首先确保委托存在。根据所需的安全级别,此检查可能需要一些同步机制

例如,如果在null检查和调用之间的另一个线程将
SomeDelegate
设置为null,则下面的代码可能抛出
NullReferenceException

if (SomeDelegate != null)
{    
  SomeDelegate();
}
以下是更安全的一点。在这里,我们利用委托是不可变的这一事实。即使另一个线程修改了
SomeDelegate
,代码也会被硬处理以防止出现讨厌的
NullReferenceException

Action local = SomeDelegate;
if (local != null)
{
  local();
}
但是,如果在另一个线程中为
SomeDelegate
分配了一个非空值,这可能会导致委托永远不会执行。这与一个微妙的记忆障碍问题有关。以下是最安全的方法

Action local = Interlocked.CompareExchange(ref SomeDelegate, null, null);
if (local != null)
{
  local();  
}
关于代理引用的方法的执行,答案是否定的。


您必须通过使用同步机制来提供自己的线程安全保障。这是因为CLR不会自动为委托的执行提供线程安全保障。可能的情况是,该方法不需要任何进一步的同步来确保安全,特别是当它从不访问共享状态时。但是,如果该方法从共享变量读取或写入,那么您必须考虑如何防止来自多个线程的并发访问。

“任何实例成员都不能保证是线程安全的。”——从您的链接中,可能会有什么变化?(你对事件的评论是正确的,但我看不出代表会有什么变化)。@agent-j:这无关紧要;底层实现可能会更改,但当前文档如前所述。或者您可以简单地将其声明为
public event SomeHandler MyEvent={}
,并保证它不为null。@Ed:这对事件有效,但对原始委托无效,因为您可以执行
SomeDelegate=null
+1,这一点很好。您可以用
Volatile.Read(ref-SomeDelegate)
替换
interlocated.compareeexchange(ref-SomeDelegate,null,null)
。请参阅。可能应该提及C#6中等效的SomeDelegate?.Invoke()语法。