C#将多个发布者事件发送给一个订阅者

时间:2014-11-04 17:43:44

标签: c# event-handling resetevent

我有一段包含两个事件处理程序的代码。我希望这两个事件处理程序通知另一个方法,即要完成一些工作。

我已经使用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再次到达Set()之前调用WaitOne()。再次到达WaitOne时,是否会等待另一个Set(),或者在到达Set()之前调用WaitOne()后继续?

这是在C#中实现多个发布者和一个订阅者模式的最佳方式吗?或者我应该使用其他东西而不是ManualResetEvent?

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

2 个答案:

答案 0 :(得分: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...集合。

答案 1 :(得分:0)

您的代码确实按照您的想法行事,您描述的竞争条件根本不是问题。根据MRE的文档,当它被设置时,它将保持在"信号发送"状态,直到通过调用WaitOne重置为止。