4

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

Communicator 有一个OnDataReceived类型 的事件EventHandler<DataReceivedEventArgs>

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

comm.OnDataReceived += consumer.PresentData;

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

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

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

4

4 回答 4

4

在你的代码中添加这个:(我通常把它放在一个名为 ISynchronizedInvoke 的静态帮助器类中,这样我就可以调用 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”上调用“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);
        }
    }
}

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

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

因此,基本上您正在创建执行调用所需的一切,并将其传递给您的通信器。这解决了您在通信器中拥有实例或引用消费者的必要性。

另请注意,我没有测试任何这些我在理论上都在做这一切,但它应该可以很好地工作。

于 2011-07-07T19:34:15.210 回答
1

尝试使用BackgroundWorker类。

于 2011-07-07T19:27:52.887 回答
1

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

于 2011-07-07T19:30:57.757 回答
1

只有当目标线程被设计为接受将方法的执行从启动线程转移到目标线程的编组操作时,您才能获得在线程上执行的方法。

让这个工作的一种方法是让你的Consumer类实现ISynchronizeInvoke。然后让您的Communicator类接受一个ISynchronizeInvoke可用于执行封送操作的实例。以System.Timers.Timer类为例。System.Timers.Timer具有SynchronizingObject可用于通过调用或将Elapsed事件编组到托管同步对象的线程上的属性。ISynchronizeInvoke.InvokeISynchronizeInvoke.BeginInvoke

棘手的部分是你如何ISynchronizeInvokeConsumer类上实现。该类启动的工作线程必须实现生产者-消费者模式才能处理委托。该BlockingCollection课程将使这相对容易,但仍有相当长的学习曲线。如果您需要更多帮助,请试一试,并提出更集中的问题。

于 2011-07-07T19:35:25.220 回答