【问题标题】:C++ boost, wait for var init from different threadC ++ boost,等待来自不同线程的var init
【发布时间】:2018-07-29 18:26:26
【问题描述】:

我的 TCP 客户端类具有向服务器发送请求的方法。 在某些情况下,我需要等待响应才能发出另一个请求。 当然我可以写这样的东西:

class MyClass {
private:
    SomeResponsMsgType* some_resp_msg_type;
    TCP_client tcp_client;

    void handle_resp(T resp) {
        //handles responses
        //initializes some_resp_msg_type and others
    }

public:
    MyClass() : some_resp_msg_type(nullptr) {}

    void init() {
        tcp_client.run(this, MyClass::handle_resp);
    }

    SomeResponsMsgType* make_request(int v) {
        Request req(v);

        some_resp_msg_type = nullptr;

        send_message(req);

        int timeout = 10;
        while(!some_resp_msg_type && !timeout) {
            Sleep(100);
            --timeout;
        }
        SomeResponsMsgType* ret = some_resp_msg_type;
        some_resp_msg_type = nullptr;

        return ret;
    }
};

//and use it like this:

void foo() {
    MyClass my_class;
    my_class.init();
    SomeResponsMsgType* resp = my_class.make_request(1);
    if(!resp)
        ...

    AnotherResponsMsgType* resp2 = my_class.make_another_request(resp->some_var);
}

但是这段代码看起来丑陋且不安全。 请帮我举个例子。谢谢。

【问题讨论】:

  • 我会使用 std::future 和 std::promise 搜索一些示例
  • 为了返回响应,您需要先从服务器获取它。此操作通常会等待。
  • @n.m.取决于“通常”。很可能,TCP_client 被设计为在这里异步运行

标签: c++ multithreading networking boost


【解决方案1】:

确实,我会在这里查看期货,并且更愿意让调用者决定何时等待值:

#include <boost/asio.hpp>
#include <iostream>
namespace ba = boost::asio;

using ba::ip::tcp;
using boost::system::error_code;
using namespace std::chrono_literals;

struct Request {
    Request(int v) : _v(v) {}
    int _v;

    friend std::ostream& operator<<(std::ostream& os, Request const& req) {
        return os << req._v;
    }
};

struct SomeResponseMsgType {
    std::string text;
};

class MyClass {
    std::future<SomeResponseMsgType> send_message(Request const& req) {
        std::promise<SomeResponseMsgType> p;

        try {
            // This would be your async call. Here I simplify by 
            tcp::iostream sock(tcp::endpoint{ {}, 6767 });
            sock.exceptions(std::ios::failbit | std::ios::eofbit | std::ios::badbit);

            sock.expires_after(1500ms);
            sock << req << "\n";

            {
                std::ostringstream oss;
                oss << sock.rdbuf();
                p.set_value(SomeResponseMsgType {oss.str()});
            }
        } catch (...) {
            p.set_exception(std::current_exception());
        }

        return p.get_future();
    }

public:
    std::future<SomeResponseMsgType> make_request(int v) {
        return send_message(Request{v});
    }
};

//and use it like this:

int main() {
    MyClass my_class;
    auto f1 = my_class.make_request(1);
    auto f2 = my_class.make_request(2);

    try {
        {
            SomeResponseMsgType resp = f2.get();
            std::cout << "Second request gave: " << resp.text << "\n";
        }
        {
            SomeResponseMsgType resp = f1.get();
            std::cout << "First request gave: " << resp.text << "\n";
        }
    } catch(boost::system::system_error const& e) {
        std::cerr << "Whoops " << e.code().message() << "\n";
    }
}

当然,在您的示例中,send_message 可能会以某种异步方式使用TCP_Client,但原理保持不变。如需更多自动化,请参阅packaged_task&lt;&gt;

请注意,这里保证了请求的顺序(因为send_message 恰好实际上是同步的)。使用异步代码,send_message 安排的异步操作的排队将决定请求是否按顺序发送。 (然后,如果服务器碰巧响应更快,第二个未来实际上可能在第一个之前准备好。)

上面的一个愚蠢的测试:

socat TCP4-LISTEN:6767,reuseaddr,fork "SYSTEM:sleep 1 && /bin/date"&
./sotest 
Second request gave: ma 30 jul 2018  1:14:42 CEST

First request gave: ma 30 jul 2018  1:14:41 CEST

【讨论】:

  • 是的,在我的情况下 TCP_Client 是异步的,但这正是我想要的!非常感谢!
  • 关于响应初始化的另一个问题。如果 TCP_Client 是异步的,我是否应该在内部创建一个带有 boost::condition_variable 的响应数组,并且“oss.str()”看起来像 { while (!response_received) condition.wait(lock);} 所以我将能够从 handle_packet 函数初始化这些响应?
  • 如果你想以异步方式处理它们,我建议使用 Boost Asio io_service(或最新的提升中的 io_context),这样你就可以避免 while很容易出错并且代码性能不佳(如果不是死锁)
  • 事实上,您可以使用 Asio 的 use_future 支持进行混搭。但我想现在这会有点复杂,所以我会尽量保持简单。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-21
  • 2020-05-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多