多线程、竞争条件和C#事件——为什么不直接尝试/捕获呢?

多线程、竞争条件和C#事件——为什么不直接尝试/捕获呢?,c#,multithreading,events,C#,Multithreading,Events,我从2009年开始关注这些问题: 我还看了Eric Lippert关于同一主题的博文: 问题似乎可以归结为,在多线程环境中,您偶尔会遇到不同线程在您的线程(线程a)“if”语句和“call delegate”语句之间注销委托的情况 当我阅读时,我想到了这个问题:如果备选方案似乎是在竞争条件或抛出的异常之间进行选择,那么为什么不将其包装在一个try/catch块中,而不用担心这两个呢?如果捕获nullReferenceException,只需在catch块中忽略它(只是为了抑制异常),然后继续

我从2009年开始关注这些问题:

我还看了Eric Lippert关于同一主题的博文:

问题似乎可以归结为,在多线程环境中,您偶尔会遇到不同线程在您的线程(线程a)“if”语句和“call delegate”语句之间注销委托的情况

当我阅读时,我想到了这个问题:如果备选方案似乎是在竞争条件或抛出的异常之间进行选择,那么为什么不将其包装在一个try/catch块中,而不用担心这两个呢?如果捕获nullReferenceException,只需在catch块中忽略它(只是为了抑制异常),然后继续


现在,我知道Eric Lippert和John Skeet对C#、多线程和委托略知一二,因此,有人能花点时间解释一下我在这里遗漏了什么吗?

这种异常吞噬的主要问题是,您无法确定
NullReferenceException
是由事件委托为
null
引起的。它可能是从委托本身内部抛出的

可以肯定的是,你说的是,而不是这样做:

Action temp = Foo;
if (temp != null)
      temp();
为此:

try {
    Foo();
}
catch (NullReferenceException e)
{
    // magically ignore it
}

因此,调用
Foo()
可能会出于多种原因导致类似的异常,您将屏蔽不相关的异常。

一般来说,当抛出异常时,意味着发生了错误


捕捉和例外并不能消除错误。你的手术仍然失败。它所做的一切就是给你一个机会,对发生的错误做出反应

也许我理解你错了,但你不可能用“试一试”就能赶上每一场比赛。请参见下面的代码

int count = 0;
for (int i = 0; i < 1000; i++) 
            Task.Factory.StartNew(()=>count++,TaskCreationOptions.LongRunning);
Console.WriteLine(count);
int count=0;
对于(int i=0;i<1000;i++)
Task.Factory.StartNew(()=>count++,TaskCreationOptions.LongRunning);
控制台写入线(计数);
这可能会在多次运行时打印其他1000

如果候补项似乎是在竞争条件或抛出的异常之间进行选择

我认为这不是这篇文章的重点

正如Eric指出的,有两个问题:

  • 委托可以为null
  • 处理者本身可能容易受到比赛条件的影响;因为注销代码类似于
    event-=handler;处置所需资源()
    并不意味着在调用dispose后处理程序代码将永远不会运行
  • 问题1通常使用临时变量解决。(如果(Foo!=null)Foo();由于竞态条件而不工作,则需要使用
    )。其他解决方法包括使用空委托初始化。在这里使用try/catch不仅会增加键入的次数,而且还会有吞噬事件处理程序中真正的NullReferenceException的危险


    通过使处理程序健壮,问题2得以解决。将整个调用放入try/catch块并不能缓解问题

    如果在catch块中要做的只是重新调用,那么try/catch有什么意义呢?关键是要抑制一个异常,在这种有限的情况下,您知道可以忽略该异常,并且您不希望最终用户必须重新启动应用程序。此外,我没有说“重新催促”。我说“扔掉它”。显然,我需要澄清这一说法。我被这个问题弄糊涂了。捕捉异常是如何消除比赛的?实际上埃里克,我是一个困惑的人。这就是为什么我发布了一个问题,实际上是“我缺少了什么?”你已经回答了,它如此简单以至于我现在有点尴尬。@EricLippert,你不知道吗?Try/Catch是所有编程错误的解决方案,您的代码示例就是我所描述的。@philologon,好的,然后,正如我所说的,无法保证您捕获的异常是由于比赛条件造成的-可能是另一个原因。如果在这种情况下,只有在特定比赛条件发生时才能捕获到特定的异常,那么捕获它就可以了。主要的一点是,即使在这里也不是这样。请注意我在我的专栏评论中对埃里克·利珀特的评论。我没有想清楚,可能在发布问题之前再考虑一下。因此,我没有正确地思考try/catch语句如何与竞争条件交互。我选择这一点作为公认的答案,因为“我缺少的”是try/catch块不能阻止竞争条件的发生,在答案级别的评论中,这是最接近于向我指出这一点的。第一个这样做的人是埃里克利珀特,但他是在评论中这样做的,而不是在回答,所以我不能认为这是被接受的。另外,其他帖子也指出了我没有意识到的信息,所以谢谢大家的评论。