将 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 相关联。

编辑 已经很长时间了,因为我已经实施了这种方法。 我已更新我的回复以反映我的选择。

  1. 我使用 windows 特定函数创建 "device" 句柄:

    HANDLE file_handle = CreateFile(... FILE_FLAG_OVERLAPPED ...);

  2. 我可以 associate/register 我的 ioService 的句柄,以便所有对设备的重叠请求都由 ioService 线程之一处理。

    error_code EC; 自动 &io_service_impl = use_service(ioservice); io_service_impl.register_handle(file_handle, EC);

  3. 然后我可以使用重叠的 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));
                });
            }
        }
    
  4. 参考设备读取实现:

    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;
    

    }