将 boost asio stream_handle与顺序的类似基于文件的设备一起使用

Using boost asio stream_handle with sequential like file based devices

本文关键字:文件 一起 于文件 stream asio boost handle 顺序      更新时间:2023-10-16

我正在考虑使用 asio 在使用 CreateFile 创建的窗口"设备句柄"上执行"重叠"(完成端口)样式的 IO(...重叠...

不过,我

有一个非常特殊的设计,由于我的应用程序的特殊性,我必须维护一个不同的线程池来执行数据的实际处理(工作池)和一个由处理池触发的实际 IO 完成池(一个非常小的池,可能只是一个线程)。

基本上,一开始我想触发一些从 IO 池发起的对我的设备的 IO 请求。当这些完成后,我会通知调度组件,该组件将完成数据包内容发布到工作池中的不同线程。这些完成通知会快速返回,因为实际处理将在工作池中发生> 并且在处理发生后从特定工作池线程启动新的"读取",该"读取"应在 io 池上触发完成。

使用窗口::stream_handle可以进行这种分离吗?通常,asio API 似乎将读取完成与流对象关联的相同io_service相关联。

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

  1. 我使用窗口特定功能创建"设备"句柄:

    句柄 file_handle = 创建文件(...FILE_FLAG_OVERLAPPED...

  2. 我可以将句柄与我的 ioService 关联/注册,以便对设备的所有重叠请求都由其中一个 ioService 线程处理。

    error_code欧共体; 自动 &io_service_impl = use_service(IO服务); 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;
    

    }