在另一个线程中运行事件处理程序(没有线程阻塞)

本文关键字:线程 程序 另一个 运行 事件处理 | 更新日期: 2023-09-27 18:01:42

我有一个类Communicator,在后台线程中工作,在TCP端口上接收数据。

通信器存在EventHandler<DataReceivedEventArgs>类型的事件OnDataReceived

还有一个类Consumer,它包含一个订阅Communicator.OnDataReceived事件的方法。

comm.OnDataReceived += consumer.PresentData;

Consumer类是在Form构造函数中创建的,然后在另一个线程中调用它的一个方法。此方法是一个无限循环,因此在应用程序执行期间,它将留在该方法中。

我想做的是让Communicator.OnDataReceived事件调用消费者线程上的consumer.PresentData方法。

这有可能吗?如果是,我应该使用什么样的机制(同步类)?

在另一个线程中运行事件处理程序(没有线程阻塞)

将此添加到代码中的某个地方:(我通常将其放在名为ISynchronizedInvoke的静态helper类中,因此我可以调用ISynchronizedInvoke. invoke(…));

public static void Invoke(ISynchronizeInvoke sync, Action action) {
    if (!sync.InvokeRequired) {
        action();
    }
    else {
        object[] args = new object[] { };
        sync.Invoke(action, args);
    }
}

然后在OnDataReceived中,你可以这样做:

Invoke(consumer, () => consumer.PresentData());

调用'consumer '。关于"消费者"的PresentData。

对于您的设计问题(消费者引用通信器),您可以在通信器中引入一个方法,如:
class Communicator {
    private ISynchronizeInvoke sync;
    private Action syncAction;
    public void SetSync(ISynchronizeInvoke sync, Action action) {
        this.sync = sync;
        this.syncAction = action;
    }
    protected virtual void OnDataReceived(...) {
        if (!sync.InvokeRequired) {
            syncAction();
        }
        else {
            object[] args = new object[] { };
            sync.Invoke(action, args);
        }
    }
}

这将为您提供一种从消费者类传入isynsynchronizedinvoke的方法。因此,您将在使用者程序集中创建isynsynchronizedinvoke。

class Consumer {
    public void Foo() {
        communicator.SetSync(this, () => this.PresentData());
    }
}

基本上你在创建所有你需要做调用的东西,并把它传递给你的通信器。这解决了在通信器中使用消费者实例或引用的必要性。

还要注意的是,我并没有测试这些,我只是在理论上这么做,但它应该可以很好地工作。

尝试使用BackgroundWorker类

这应该是可能的。您可以创建一个队列来执行,或者查看Dispatcher对象,如果有帮助的话,将一些方法推入UI线程是有用的(有时是强制性的,是唯一的方法)。

只有当目标线程设计为接受封送操作,将方法的执行从初始线程转移到目标线程时,才能在线程上执行方法。

让这个工作的一种方法是让你的Consumer类实现ISynchronizeInvoke。然后让Communicator类接受一个ISynchronizeInvoke实例,它可以使用该实例执行封送处理操作。以System.Timers.Timer类为例。System.Timers.Timer具有SynchronizingObject属性,它可以通过调用ISynchronizeInvoke.InvokeISynchronizeInvoke.BeginInvokeElapsed事件封送到承载同步对象的线程上。

棘手的部分是如何在Consumer类上实现ISynchronizeInvoke。由该类启动的工作线程必须实现生产者-消费者模式才能处理委托。BlockingCollection类将使这相对容易,但仍然有相当的学习曲线。试一试,如果你需要更多的帮助,再回复一个更有针对性的问题。