我正在使用boost:asio和多个io_services来保持不同形式的阻塞I / O分离。例如。我有一个io_service用于阻塞文件I / O,另一个用于长时间运行的CPU绑定任务(这可以扩展到第三个用于阻止网络I / O等)一般来说我想确保一种形式的阻止I / O不会使其他人挨饿。
我遇到的问题是,因为在一个io_service中运行的任务可以将事件发布到其他io_service(例如,CPU绑定的任务可能需要启动文件I / O操作,或者完成的文件I / O操作可能会调用一个CPU绑定的回调),我不知道如何保持两个io_services运行,直到它们都没有事件。
通常使用单个I / O服务,您可以执行以下操作:
shared_ptr<asio::io_service> io_service (new asio::io_service);
shared_ptr<asio::io_service::work> work (
new asio::io_service::work(*io_service));
// Create worker thread(s) that call io_service->run()
io_service->post(/* some event */);
work.reset();
// Join worker thread(s)
但是,如果我只是为两个io_services执行此操作,那么我没有发布初始事件的那个会立即完成。即使我将初始事件发布到两者,如果io_service B上的初始事件在io_service A上的任务之前完成,则向B发布新事件,io_service B将提前完成。
如何在io_service A仍在处理事件时保持io_service B运行(因为服务A中的一个排队事件可能会向B发布新事件),反之亦然,同时仍然确保两个io_services都退出运行()方法,如果它们同时出现在两个事件之外?
答案 0 :(得分:3)
找出一种方法来做到这一点,所以如果其他人在搜索中发现了这个问题,请将其记录下来以备记录:
创建每个N个交叉通信的io_services,为每个io_services创建一个工作对象,然后启动它们的工作线程。
创建一个“master”io_service对象,该对象不会运行任何工作线程。
不允许将事件直接发布到服务。相反,为io_services创建访问器函数:
在主要的执行流程中,一旦所有N io_services都已启动并且您已将工作发布到至少其中一个,请在主io_service上调用run()。
当主io_service的run()方法返回时,删除N交叉通信io_services上的所有初始工作,并加入所有工作线程。
让主io_service的线程自己在其他每个io_services上工作,确保它们不会在master io_service失去工作之前终止。让每个其他io_services在每个发布的回调的主io_service上工作,确保master io_service在其他每个io_services不再有任何已发布的回调留待处理之前不会失去工作。
一个例子(可以在类中封装):
shared_ptr<boost::asio::io_service> master_io_service;
void RunWorker(boost::shared_ptr<boost::asio::io_service> io_service) {
io_service->run();
}
void RunCallbackAndDeleteWork(boost::function<void()> callback,
boost::asio::io_service::work* work) {
callback();
delete work;
}
// All new posted callbacks must come through here, rather than being posted
// directly to the io_service object.
void PostToService(boost::shared_ptr<boost::asio::io_service> io_service,
boost::function<void()> callback) {
io_service->post(boost::bind(
&RunCallbackAndDeleteWork, callback,
new boost::asio::io_service::work(*master_io_service)));
}
int main() {
vector<boost::shared_ptr<boost::asio::io_service> > io_services;
vector<boost::shared_ptr<boost::asio::io_service::work> > initial_work;
boost::thread_pool worker_threads;
master_io_service.reset(new boost::asio::io_service);
const int kNumServices = X;
const int kNumWorkersPerService = Y;
for (int i = 0; i < kNumServices; ++i) {
shared_ptr<boost::asio::io_service> io_service(new boost::asio::io_service);
io_services.push_back(io_service);
initial_work.push_back(new boost::asio::io_service::work(*io_service));
for (int j = 0; j < kNumWorkersPerService; ++j) {
worker_threads.create_thread(boost::bind(&RunWorker, io_service));
}
}
// Use PostToService to start initial task(s) on at least one of the services
master_io_service->run();
// At this point, there is no real work left in the services, only the work
// objects in the initial_work vector.
initial_work.clear();
worker_threads.join_all();
return 0;
}
答案 1 :(得分:2)
HTTP server example 2做了类似的事情,你可能觉得有用。它使用io_service
池的概念,为vector
保留shared_ptr<boost::asio::io_service>
个shared_ptr<boost::asio::io_service::work>
和io_service
io_service
。它使用线程池来运行每个服务。
该示例使用循环调度将工作分配给I / O服务,我认为这不适用于您的情况,因为您有io_service
A和{{1}的特定任务B。