【发布时间】:2021-12-14 22:55:18
【问题描述】:
我试图更好地理解异步 asio 的工作原理。
我有以下代码,我在套接字上调用 async_read 以读取接下来的 10 个字节的数据。
struct SocketReader {
void do_read_body()
{
asio::async_read(socket_,
asio::buffer(msg_, 10),
[this](asio::error_code ec, std::size_t length)
{
if (!ec)
{
//messages_to_work_on.emplace_back(msg_); // <-- I'm trying to send this msg_ instance to another io_context
do_read_body(); // call again
}
else
{
socket_.close();
}
});
}
std::vector<uint8_t> msg_;
asio::tcp::socket _socket;
}
这些读取是在他自己的 std::thread 中运行的 io_context 内完成的,我在队列中收集从套接字读取的所有消息。到目前为止一切顺利。
我还有另一个“工人”类,它只是根据队列中可用的内容执行一些工作:
struct Worker
{
asio::io_context& io_context_;
std::deque< std::vector<uint8_t> > queue;
Worker(asio::io_context& io_context)
: io_context_(io_context) {
asio::post(io_context_, [this]() {doWork();});
}
void doWork() {
if (!queue.empty())
{
// do some work with front()
queue.pop_front();
}
asio::post(io_context_, [this]() {doWork();});
}
};
那个也在他自己的io_context中执行,在他自己的线程中运行。所以socket线程和worker线程之间是有并发的。
将从套接字接收的数据发布到工人类的正确方法是什么? 我在想我应该能够从套接字完成处理程序中调用,例如:
asio::post(worker_io_context, [this]() {worker.queue.push_back(msg_)});
这样,我至少可以确定没有同时使用工作队列。 但我不确定是否允许我从一个 io_context 发布到另一个,以及我是否不会以这种方式创建另一个竞争条件。 我也不太明白我的消息的内存应该放在哪里,尤其是从一个 io_context 到另一个的传输“中间”。是否需要按值传递消息(因为 this.msg_ 可以在执行后处理程序之前修改)?
谢谢!
【问题讨论】:
-
我不明白为什么这么复杂 - 只需调用函数 doWork() 而不是“messages_to_work_on.emplace_back(msg_);”并且您将获得预期的行为,没有“双端队列”,没有竞争条件,没有头痛,没有两个 io_contexts,没有两个线程。
-
@Heto 关键是 do_work 可能正在进行长时间运行的计算,所以我不想阻塞正在读取套接字的线程(你建议这样做)。相反,我想在另一个线程(另一个 io_context)中发送数据,以便可以在不阻塞其余线程的情况下处理它
标签: c++ boost-asio