c++ - Boost.Asio 设计的示例莫名其妙地阻塞

标签 c++ boost-asio

我广泛使用了 Boost.Asio,但我遇到了一个我不理解的单元测试问题。我已将问题简化为一个非常人为的示例:

#include <string>
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>

#include <boost/asio.hpp>
#define BOOST_TEST_MODULE My_Module
#define BOOST_TEST_DYN_LINK
#include <boost/test/unit_test.hpp>
#include <boost/test/auto_unit_test.hpp>

using namespace std::string_literals;
using namespace std::chrono_literals;

namespace BA = boost::asio;
namespace BAI = BA::ip;

BOOST_AUTO_TEST_CASE(test)
{
    std::mutex m;
    std::condition_variable cv;

    BA::io_service servicer;
    auto io_work = std::make_unique<BA::io_service::work>(servicer);

    auto thread = std::thread{[&]() {
        servicer.run();
    }};

    auto received_response = false;

    auto server_buf = std::array<std::uint8_t, 4096>{};
    auto server_sock = BAI::tcp::socket{servicer};
    auto acceptor = BAI::tcp::acceptor{servicer,
                                       BAI::tcp::endpoint{BAI::tcp::v4(), 20123}};
    acceptor.async_accept(server_sock, [&](auto&& ec) {
        if (ec) {
            BOOST_TEST_MESSAGE(ec.message());
        }
        BOOST_REQUIRE(!ec);

        BOOST_TEST_MESSAGE("Accepted connection from " << server_sock.remote_endpoint() <<
                           ", reading...");

        BA::async_read(server_sock,
                       BA::buffer(server_buf),
                       [&](auto&& ec, auto&& bytes_read){
            std::unique_lock<decltype(m)> ul(m);
            received_response = true;

            if (ec) {
                BOOST_TEST_MESSAGE(ec.message());
            }
            BOOST_REQUIRE(!ec);

            const auto str = std::string{server_buf.begin(),
                                         server_buf.begin() + bytes_read};
            BOOST_TEST_MESSAGE("Read: " << str);

            ul.unlock();
            cv.notify_one();
        });
    });

    const auto send_str = "hello"s;
    auto client_sock = BAI::tcp::socket{servicer, BAI::tcp::v4()};
    client_sock.async_connect(BAI::tcp::endpoint{BAI::tcp::v4(), 20123},
                              [&](auto&& ec) {
        if (ec) {
            BOOST_TEST_MESSAGE(ec.message());
        }
        BOOST_REQUIRE(!ec);

        BOOST_TEST_MESSAGE("Connected...");
        BA::async_write(client_sock,
                        BA::buffer(send_str),
                        [&](auto&& ec, auto&& bytes_written) {
            if (ec) {
                BOOST_TEST_MESSAGE(ec.message());
            }
            BOOST_REQUIRE(!ec);

            BOOST_TEST_MESSAGE("Written " << bytes_written << " bytes");
        });
    });

    std::unique_lock<decltype(m)> ul(m);
    cv.wait_for(ul, 2s, [&](){ return received_response; });
    BOOST_CHECK(received_response);

    io_work.reset();
    servicer.stop();
    if (thread.joinable()) {
        thread.join();
    }
}

我用它编译:

g++ -std=c++17 source.cc -l boost_unit_test_framework -pthread -l boost_system -ggdb

输出是:

Accepted connection from 127.0.0.1:51688, reading...
Connected...
Written 5 bytes

然后超时。

运行调试器显示 async_read 处理程序从未被调用。在它似乎没有做任何事情的阶段暂停执行,表明主线程正在等待 condition_variable (cv) 和 io_service 线程在 epoll_wait 上。

我似乎陷入了僵局,但看不出如何。

最佳答案

这就是函数定义的工作方式,它等待缓冲区有空间的字节数(http://www.boost.org/doc/libs/1_62_0/doc/html/boost_asio/reference/async_read/overload1.html)。

试试这个:http://www.boost.org/doc/libs/1_62_0/doc/html/boost_asio/reference/async_read/overload2.html

您可以提供回调来决定读取是否完成,这可能包括在编写者写入消息后等待和检查另一个 channel 提供的长度(如果您确定了一种无死锁的方式来做到这一点) 或就在消息本身之前。

添加这个完成条件使其工作:

[&](auto&& ec, auto&& bytes_read){
    return bytes_read < 5 ? 5 - bytes_read : 0;
},

关于c++ - Boost.Asio 设计的示例莫名其妙地阻塞,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45927173/

相关文章:

c++ - 如何确定我的程序还剩多少虚拟内存?

c++ - 从包装器中提取到 vector map

c++ - 忽略另一个内部的连接组件

c++ - 为什么 std::bind 和 boost::bind 在这个 Boost.Asio 教程中不能互换使用

c++ - Boost Windows 程序是否可以移植到其他 Windows 系统?

c++ - boost Asio Peek 和完成条件

c++ - 我的服务器以代码 137 退出

c++ - std::chrono:将自定义持续时间添加到 time_point

c++ - 用于增强现实的 OpenCV 相机内在矩阵到 Ogre 投影矩阵

c++ - 如何找出通过 Boost ASIO TCP 套接字连接发送了多少数据?