2

我正在使用 AutoResetEvent,其中可以对事件进行多个 Set 调用(异常处理)。有时会调用额外的 Set,因此当代码对 WaitOne 事件进行第二次调用时,它会直接通过,因为门已经打开。

解决方案是在 WaitOne 之前调用 Reset。有没有更清洁的解决方案,或者这是唯一的方法?示例代码:

private void DoSomeWork()
{
    Thread thrd = new Thread(new ThreadStart(DoSomeOtherStuff));
    thrd.Start();

    //mEvt.Reset();
    mEvt.WaitOne();

    //continue with other stuff
}

private void DoSomeOtherStuff()
{
    /* lots of stuff */

    mEvt.Set();
}

private void ExceptionTriggerNeedsToBreakOutOfDoSomeWork()
{
   mEvt.Set();
}

处理完异常后,我需要再次调用 DoSomeWork,但由于 Set 可能已在多个异常中调用(或重新抛出异常),WaitOne 只是流过。

我的解决方案是始终在 WaitOne 之前调用 Reset。这是合适的解决方案、糟糕的设计,还是有不同类型的事件可以处理这种情况?

编辑:我刚刚将评论的重置(建议的解决方案)移到了事件旁边。

4

2 回答 2

4

这不是真正的问题,WaitOne() 调用会自动重置事件。毕竟,您使用的是 AutoResetEvent,而不是 ManualResetEvent。这里的关键词是自动重置。

通过 WaitOne() 调用看到它正在冒气也很正常。您有一个不错的多核 CPU,当您调用 Start() 时线程立即启动并且只需要几微秒即可完成工作。毫秒,无论如何,比眨眼还快。

也许更重要的是,您在这里不需要线程。开始一个,然后等待它完成是没有意义的。只需直接调用 DoSomeOtherStuff() 即可。

于 2010-11-05T20:50:37.440 回答
2

我担心的是,如果你在 WaitOne() 之前调用 Reset(),如果没有调用 Set(),你就会遇到麻烦。如果您调用 Set(),然后在点击 WaitOne() 之前立即点击 Reset(),则可能会发生这种情况。即使您调用 Set() 两次,也不能保证您不会在两次调用 Reset() 之后,阻塞线程而没有释放机制。

理想情况下,您应该有一个 try..catch..finally 块,并在 finally 块中调用 Set(),并且不会让您的异常处理跨方法传播。那对你有用吗?

汉斯是正确的,在这种情况下,多线程是不必要的。我的担忧仅适用于您真正对 WaitOne() 的调用进行多线程处理的情况。

我还担心你不止一次调用 set ......这是否意味着当第一个 set 被调用时,资源真的应该保持锁定状态?如果您仍然能够再次点击 Set(),对我来说,这说明您仍在执行适用于共享资源的代码。在这种情况下,您不希望对 WaitOne() 的调用解除阻塞。

另请注意,来自 MSDN:

不能保证每次调用 Set 方法都会释放一个线程。如果两个调用靠得太近,以至于第二个调用发生在一个线程被释放之前,那么只有一个线程被释放。就好像第二次通话没有发生一样。

无论如何,您的代码似乎应该要么抛出异常,要么运行完成,但不能两者兼而有之。IE 你不应该调用 Set() 两次。

于 2010-11-05T21:02:11.733 回答