2014-11-04 77 views
0

我有一段代码有两个事件处理程序。我希望这两个事件处理程序通知另一种方法,即有一些工作要做。C#事件多个发布者到一个订阅者

我已经实现了这个使用ManualResetEvent,但我不确定这是否是实现我想要的最好方法,或者是否有更好的方法。

static ManualResetEvent autoEvent = new ManualResetEvent(false); 

void begin() { 
    ThreadPool.QueueUserWorkItem(new WaitCallback(genericHandler)); 
} 

void OnEvent1(object sender) { 
    autoEvent.Set(); 
} 

void OnEvent2(object sender) { 
    autoEvent.Set(); 
} 

void genericHandler(object info) { 
    while (true) { 
     autoEvent.WaitOne(); 
     // do some work 
    } 
} 

一个我拥有的最重要的问题是:autoEvent.WaitOne()后,我做了一些工作,这些工作耗费的时间。与此同时,另一个事件被触发,并且在genericHandler再次获得WaitOne()之前调用Set()。当再次到达WaitOne时,它是否会等待另一个Set(),或者在达到WaitOne()之前调用Set()之前继续?

这是在C#中实现多个发布者和一个订户模式的最佳方式吗?或者我应该使用另一件事物而不是ManualResetEvent?

注意:genericHandler位于不同的线程中,因为Event1和Event2具有不同的优先级,所以在处理程序中,我会在检查Event2之前检查Event1是否有挂起的工作。

回答

0

你的代码确实做了你认为它所做的事情,你描述的竞争条件根本不是问题。按照MRE的文件,当它被设置时,它将保持在“信号”状态,直到通过呼叫WaitOne重置为止。

+0

如果在我做这项工作时有两个信号会怎么样? WaitOne会知道Set()被调用两次,而不是等到另一个Set被调用? – BlunT 2014-11-04 18:03:05

+0

@BlunT号对于这种行为,你需要一个'Semaphore',它将是一个围绕一个整数的线程安全包装,而不是一个MRE,它在概念上是布尔“isSignaled”值的包装。 – Servy 2014-11-04 18:04:25

+0

好吧,那正是我的恐惧。我看了Semaphore,但我认为Release是不合适的。也许我错过了一些东西。我需要一些增量方法,然后WaitOne()在处理程序的权利?我应该用什么来保持增加信号计数,而不是Set()? – BlunT 2014-11-04 18:08:35

0

问题和代码太模糊地提出,以提供良好的具体建议。这就是说...

不,使用ManualResetEvent在这里不合适。它不仅不必要地使代码复杂化,而且代码依赖于从线程池中取得的长时间运行的线程(只执行短期任务)。

如果您需要触发执行某些异步工作的事件,那么您应该使用async/await模式,其中每个新工作单元都通过Task类调​​用。

例如:

async void OnEvent1(object sender) { 
    var workUnit = ... ; // something here that represents your unit of work 
    await Task.Run(() => genericHandler(workUnit)); 
} 

void OnEvent2(object sender) { 
    var workUnit = ... ; // something here that represents your unit of work 
    await Task.Run(() => genericHandler(workUnit)); 
} 

void genericHandler(object info) { 
    // do some work using info 
} 

注意,事件对象以及begin()方法完全消除。

从你的问题来看,并不清楚每个工作单位是否完全相互独立。如果不是,那么您可能还需要一些同步来保护共享数据。再次,没有一个更具体的问题,不可能说出这将是什么,但最有可能使用lock声明或Concurrent...集合之一。

+0

我会为该问题添加更多详细信息,因为您的答案似乎不符合我的要求。我需要事件不直接调用genericHandler的主要原因之一是因为Event1和Event2具有不同的优先级。而且由于处理它们每一个都需要时间,所以我需要首先检查其中之一是否有待处理的工作,因此是单独的处理程序。 – BlunT 2014-11-04 18:01:15

+0

如果优先级较低的事件首先发生会发生什么?如果提高优先级事件,它的工作是否会中断?如果没有,那么你真的只是在谈论同步(正如我在我的回答中提到的)。如果优先级较高的事件可以从优先级较低的事件中断工作,那么在您给出的示例中这是如何实现的?你仍然可以使用我建议的方法,你只需要在工作人员中包括取消支持(即对每项任务使用'CancellationToken') – 2014-11-04 18:08:00

相关问题