0

我从 2009 年开始研究这些问题: C# Events and Thread Safety

我还查看了 Eric Lippert 关于同一主题的博客文章:http: //blogs.msdn.com/ericlippert/archive/2009/04/29/events-and-races.aspx

问题似乎归结为,在多线程环境中,您偶尔会遇到不同线程取消注册线程(线程 A)“if”语句和“调用委托”语句之间的委托的情况。

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

现在,我了解 Eric Lippert 和 John Skeet 对 C#、多线程和委托有一点了解,所以有人可以花点时间解释一下我在这里缺少什么吗?

4

4 回答 4

2

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

只是为了确定-您要说的是,而不是这样做:

Action temp = Foo;
if (temp != null)
      temp();

去做这个:

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

同样,由于许多原因,该Foo()调用可能会导致类似的异常,并且您将屏蔽不相关的异常。

于 2013-01-08T22:49:47.853 回答
2

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

捕捉和异常不会使错误消失。您的操作仍然失败。它所做的只是让你有机会对正在发生的错误做出反应。

于 2013-01-08T22:51:28.063 回答
2

如果备选方案似乎是竞争条件或抛出异常之间的选择

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

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

  1. 委托可能为空
  2. 处理程序本身可能容易受到竞争条件的影响;仅仅因为取消注册的代码类似于event -= handler; DisposeRequiredResources();,并不意味着处理程序代码在调用 dispose 后将永远不会运行。

问题 1 通常使用临时变量来解决。(它是必需的,if (Foo != null) Foo();由于竞争条件而不起作用)。其他解决方法包括使用空委托进行初始化。在这里使用 try/catch 不仅需要更多的输入,它还有在事件处理程序中吞下真正的 NullReferenceExceptions 的危险。

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

于 2013-01-08T23:00:03.813 回答
1

也许我理解错了,但你不能只用 try-catch 来捕捉每一个比赛条件。请参阅下面的代码

int count = 0;
for (int i = 0; i < 1000; i++) 
            Task.Factory.StartNew(()=>count++,TaskCreationOptions.LongRunning);
Console.WriteLine(count);

多次运行时,这可能会打印 1000 以外的内容。

于 2013-01-08T22:53:28.720 回答