将 boost asio stream_handle 与基于序列的类似文件的设备一起使用
Using boost asio stream_handle with sequential like file based devices
我正在考虑使用 asio 在使用 CreateFile(...overlapped...)[=11 创建的 windows "device handle" 上执行 "overlapped"(完成端口)样式 IO =]
虽然我有一个非常特别的设计,但由于我的应用程序的细节,我必须维护一个不同的线程池来执行数据的实际处理(工作池)和一个池(一个非常小的,可能只是一个线程可能)由处理池触发的实际 IO 完成。
基本上,一开始我想向我的设备触发一些从 IO 池发起的 IO 请求。当这些完成时,我通知调度组件 POSTS 完成数据包内容到工作池中的不同线程。这些完成通知 return 很快,因为实际处理将在工作池中进行 -> 并且在处理发生后从特定工作池线程启动一个新的 "read" 应该触发 io 池上的完成。
是否可以使用 windows::stream_handle 进行解离?一般来说,asio API 似乎将读取完成与与流对象关联的相同 io_service 相关联。
编辑
已经很长时间了,因为我已经实施了这种方法。
我已更新我的回复以反映我的选择。
我使用 windows 特定函数创建 "device" 句柄:
HANDLE file_handle = CreateFile(... FILE_FLAG_OVERLAPPED ...);
我可以 associate/register 我的 ioService 的句柄,以便所有对设备的重叠请求都由 ioService 线程之一处理。
error_code EC;
自动 &io_service_impl = use_service(ioservice);
io_service_impl.register_handle(file_handle, EC);
然后我可以使用重叠的 asio 从与 ioService.run() 不同的线程启动异步 IO,使其在 io 服务线程中触发完成:
void IoPool::InitiateNewRead()
{
service.post([this]() {auto handler = InterceptorReadHandler::Create(bufferPool, data, service);
handler->SetContext(context);
return device.Read(std::move(handler));
});
}
}
参考设备读取实现:
bool Device::Read(std::shared_ptr<InterceptorReadHandler> handler) {
auto handlerWrapper = [handler](const boost::system::error_code &ec, std::size_t len) {
handler->Completion(ec, len);
};
win::overlapped_ptr overlapped(handler->GetService(), handlerWrapper);
unsigned long bytesRead = 0;
auto& packet = handler->GetBuffer();
auto ok = ::ReadFile(handle,
packet.data,
static_cast<DWORD> (packet.length),
&bytesRead,
overlapped.get()) ? true : false;
auto lastError = ::GetLastError();
if (!ok && lastError != ERROR_IO_PENDING) {
boost::system::error_code errCode(lastError, boost::system::get_system_category());
overlapped.complete(errCode, 0);
return false;
} else {
overlapped.release();
}
return true;
}
我正在考虑使用 asio 在使用 CreateFile(...overlapped...)[=11 创建的 windows "device handle" 上执行 "overlapped"(完成端口)样式 IO =]
虽然我有一个非常特别的设计,但由于我的应用程序的细节,我必须维护一个不同的线程池来执行数据的实际处理(工作池)和一个池(一个非常小的,可能只是一个线程可能)由处理池触发的实际 IO 完成。
基本上,一开始我想向我的设备触发一些从 IO 池发起的 IO 请求。当这些完成时,我通知调度组件 POSTS 完成数据包内容到工作池中的不同线程。这些完成通知 return 很快,因为实际处理将在工作池中进行 -> 并且在处理发生后从特定工作池线程启动一个新的 "read" 应该触发 io 池上的完成。
是否可以使用 windows::stream_handle 进行解离?一般来说,asio API 似乎将读取完成与与流对象关联的相同 io_service 相关联。
编辑 已经很长时间了,因为我已经实施了这种方法。 我已更新我的回复以反映我的选择。
我使用 windows 特定函数创建 "device" 句柄:
HANDLE file_handle = CreateFile(... FILE_FLAG_OVERLAPPED ...);
我可以 associate/register 我的 ioService 的句柄,以便所有对设备的重叠请求都由 ioService 线程之一处理。
error_code EC; 自动 &io_service_impl = use_service(ioservice); io_service_impl.register_handle(file_handle, EC);
然后我可以使用重叠的 asio 从与 ioService.run() 不同的线程启动异步 IO,使其在 io 服务线程中触发完成:
void IoPool::InitiateNewRead() { service.post([this]() {auto handler = InterceptorReadHandler::Create(bufferPool, data, service); handler->SetContext(context); return device.Read(std::move(handler)); }); } }
参考设备读取实现:
bool Device::Read(std::shared_ptr<InterceptorReadHandler> handler) { auto handlerWrapper = [handler](const boost::system::error_code &ec, std::size_t len) { handler->Completion(ec, len); }; win::overlapped_ptr overlapped(handler->GetService(), handlerWrapper); unsigned long bytesRead = 0; auto& packet = handler->GetBuffer(); auto ok = ::ReadFile(handle, packet.data, static_cast<DWORD> (packet.length), &bytesRead, overlapped.get()) ? true : false; auto lastError = ::GetLastError(); if (!ok && lastError != ERROR_IO_PENDING) { boost::system::error_code errCode(lastError, boost::system::get_system_category()); overlapped.complete(errCode, 0); return false; } else { overlapped.release(); } return true;
}