我想使用boost::asio(或独立于asio)每分钟通过异步套接字查询多个网络设备以获取数据。为了进行测试,我已经实现了Client类和一个控制台程序,该程序可以在一台设备上执行该操作(无重复)。
像这样的东西:

class MyClient
{
public:
    MyClient(asio::io_service& io_service);

    void GetData(CompletionHandler completionHandler);
};

MyClient::GetData类在内部使用多个异步操作,其中每个操作的完成都会触发下一个操作,直到数据可用为止:
  • 连接
  • 读取头
  • 读取数据
  • 断开

  • 使用此类的控制台程序的工作原理如下:
    int main(...)
    {
        asio::io_service io_service_;
    
        MyClient c(io_service_, ...);
        ...
        c.GetData([](std::error_code ec, const FloatVector& values){
            //do something with values
        });
    
        io_service_.run();
        ...
    }
    

    现在,我想在GUI程序中使用MyClient类每分钟一次连接到10台以上的设备,但是我在总体设计上陷入了困境。

    首先,我创建了一个线程池,其中每个线程都执行单个io_service实例的io_service::run()。

    现在,只要我的程序想要从设备读取数据,它就会在所有设备上循环,并且必须为每个设备创建MyClient实例并调用GetData()方法。

    现在在池的线程中执行了io_service::run()之后,它如何与io_service一起使用?我可以简单地在GUI线程中调用MyClient::GetData(),因为它在内部使用异步操作,还是必须调用io_service::post()之类的东西?

    更新:
    我的代码和控制台演示大致遵循以下示例:
    www.boost.org/doc/libs/1_36_0/doc/html/boost_asio/example/http/client/async_client.cpp

    但是在GUI程序中,我不想在GUI线程中运行io_service.run()。现在假设我至少有一个额外的线程执行io_service.run(),并且用户按下了应该开始读取设备的按钮。最终完成处理程序应将数据存储在数据库中,并向用户更新图形显示。

    也许按钮处理程序可以简单地实例化MyClient并在其上调用GetData(),并且一切正常,因为MyClient知道io_service并使用它。在async_connect等中

    像这样工作还是我在这里弄错了?

    注意:这时我的问题不是如何在完成处理程序中处理数据!这是在多线程GUI程序中正确获取数据的方法。

    最佳答案

    以下是您需要做什么的粗略概述:

  • 首先请注意,如果io_service.run()没有任何工作要做,它将立即返回。因此,根据您的工作流程,您可能需要推迟对其进行调用,直到您真正使第一个异步连接排队为止。如果查看示例客户端,您会首先看到实例化了客户端,该客户端将第一个操作(在这种情况下为异步解析)排队,然后调用io_service.run()。
  • 因此,假设您从一个按钮开始,请按此刻要做的是安排连接或解析,然后启动一个新线程并从该线程中调用io_service.run()。
  • 一旦异步操作链完成并且您拥有了数据,您的处理程序将在您创建的新线程的上下文中被调用。这意味着您必须将消息发布回您的UI(因为通常UI工作只能在主线程上完成)。例如。您的示例中的lambda需要执行某种UI post消息操作(详细信息取决于我们在此讨论的OS/GUI)。
  • 然后您的GUI线程将接收该消息并更新您想要更新的任何UI状态(例如,显示结果)
  • 10-08 08:16
    查看更多