简体   繁体   English

C# .NET 3.5:如何调用事件处理程序并等待它完成

[英]C# .NET 3.5 : How to invoke an event handler and wait for it to complete

I have a class containing a worker thread which receives data from a queue in a loop.我有一个 class 包含一个工作线程,该线程从循环中的队列接收数据。

Another part of the app sinks an event from this class, which the class raises for each queue item.应用程序的另一部分从该 class 接收一个事件,class 为每个队列项引发该事件。

These events are fired asynchronously, so at busy times the other part of the app can be processing several events at once.这些事件是异步触发的,因此在繁忙时间应用程序的其他部分可以同时处理多个事件。

This should be fine but we've discovered a scenario where this can cause problems.这应该没问题,但我们发现了一个可能导致问题的场景。

We need a quick solution while the main issue gets addressed.在解决主要问题时,我们需要一个快速的解决方案。 Does the framework provide a simple way I can force the worker thread to wait while each event gets processed (so they are processed sequentially)?该框架是否提供了一种简单的方法,我可以强制工作线程在处理每个事件时等待(因此它们是按顺序处理的)? If not, what's the easiest way to implement this?如果没有,实现这一点的最简单方法是什么?

A simple answer would be to lock() on a single object in the event handler.一个简单的答案是 lock() 在事件处理程序中的单个 object 上。 All of the theads would wait to get the lock.所有的tads都将等待获得锁。

The ManualResetEvent class might help you here, unless I'm not understanding your question. ManualResetEvent class在这里可能对您有所帮助,除非我不理解您的问题。 You can use it to block the firing of the next event until the last one completes.您可以使用它来阻止下一个事件的触发,直到最后一个事件完成。

My guess is that you want to simply go away from triggering the action by raising an event and calling the method directly.我的猜测是,您只想通过引发事件并直接调用该方法来使 go 远离触发动作。

AFAIK events are going to be async and I am not aware of any "easy" ways of changing that. AFAIK 事件将是异步的,我不知道有任何“简单”的方法来改变它。

Turns out there's another answer.原来还有另一个答案。 You can just add the following attribute to the method.您可以将以下属性添加到方法中。

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]

There is no general way.没有通用的方法。

In the end the handlers need to provide a mechanism for tracking.最后,处理程序需要提供一种跟踪机制。

If you are using BeginInvoke, rather than raising the events directly, you can use a wrapper, within which you call the real event handler synchronously, then raise the wrapper asynchronously.如果您使用 BeginInvoke,而不是直接引发事件,则可以使用包装器,在其中同步调用真实事件处理程序,然后异步引发包装器。 The wrapper can maintain a counter (with Interlocked operations) or set an event as meets your needs.包装器可以维护一个计数器(具有互锁操作)或根据您的需要设置一个事件。

Something like:就像是:

TheDelegate realHandler = theEvent;
var outer = this;
ThreadPool.QuereUserWorkItem(x => {
  // Set start of handler
  realHandler(outer, eventArgs);
  // Set handler finished
};

All of the event handlers sinking events raised by the queue-reading worker thread are called in the queue-reading worker thread.所有接收队列读取工作线程引发的事件的事件处理程序都在队列读取工作线程中调用。 As long as the event handlers aren't spawning threads of their own, you should be able to wait for the event handlers to finish by calling Thread.Join() on the queue-reading worker thread.只要事件处理程序不产生自己的线程,您就应该能够通过在队列读取工作线程上调用 Thread.Join() 来等待事件处理程序完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM