【发布时间】:2020-07-05 11:09:33
【问题描述】:
我正在尝试对 DeviceIOControl 执行异步调用,目的是在设备完成请求后,将调用关联的处理程序。
我有一个使用 winapi 的工作代码,它按预期工作。然而,使用 boost::asio 的等效代码并不相同。 代码执行以下操作:
- 初始化 IO 完成端口 (CreateIoCompletionPort / boost::asio::io_context)
- 使用 OVERLAPPED_FLAG 创建设备 HANDLE
- 将 HANDLE 与具有 IO 完成端口的设备相关联 (CreateIoCompletionPort / boost::asio::detail::io_context_impl::register_handle)
- 使用 OVERLAPPED 结构执行单个 DeviceIOControl (boost::asio::windows::overlapped_ptr)
- 等待调用完成 (GetQueuedCompletionStatus / boost::asio::io_context::run)
这是 WinAPI 代码(有效)
auto iocp_handle = ::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, 0);
assert(iocp_handle);
auto str = GetDeviceInterfaceInstancesList(&GUID_DEVINTERFACE_cvbkmd);
HANDLE dev_handle = CreateFileW(
str.c_str(),
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
nullptr
);
uint64_t completion_key = 3082;
assert(::CreateIoCompletionPort(dev_handle, iocp_handle, completion_key, 0));
std::string writeString = "test write\n";
std::string readString = "test read\n";
unsigned long bytes_returned;
OVERLAPPED overlapped{};
BOOL ok = DeviceIoControl(
dev_handle,
123,
writeString.data(),
writeString.size(),
readString.data(),
readString.size(),
&bytes_returned,
&overlapped
);
if (ok)
{
std::cout << "done\n";
}
else
{
auto err = GetLastError();
assert(err == ERROR_IO_PENDING);
OVERLAPPED* returned_overlapped{ nullptr };
uint64_t returned_completion_key{};
unsigned long bytes_transferred;
BOOL ok = ::GetQueuedCompletionStatus(iocp_handle,
&bytes_transferred, &returned_completion_key, &returned_overlapped,
INFINITE);
assert(ok);
assert(returned_completion_key = completion_key);
assert(returned_overlapped = &overlapped);
}
这是 boost::asio 代码(io_context::run 永远挂起,从未调用完成处理程序)
boost::asio::io_context context;
auto str = GetDeviceInterfaceInstancesList(&GUID_DEVINTERFACE_cvbkmd);
HANDLE dev_handle = CreateFileW(
str.c_str(),
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
nullptr
);
auto& impl = boost::asio::use_service<boost::asio::detail::io_context_impl>(context);
boost::system::error_code ec;
impl.register_handle(dev_handle, ec);
assert(!ec);
boost::asio::windows::overlapped_ptr overlapped(
context,
[&](const boost::system::error_code& ec, std::size_t count)
{
std::cout << "done"; // never called
}
);
std::string writeString = "test write\n";
std::string readString = "test read\n";
unsigned long bytes_returned;
BOOL ok = DeviceIoControl(
dev_handle,
123,
writeString.data(),
writeString.size(),
readString.data(),
readString.size(),
&bytes_returned,
overlapped.get()
);
if (ok)
{
std::cout << "done\n";
}
else
{
auto err = GetLastError();
assert(err == ERROR_IO_PENDING);
auto completions = context.run(); // hangs forever
assert(completions == 1);
}
问题
- 为什么 2 个代码段的行为不同?
- 为什么 boost::asio::io_context::run 挂起并且与overlapped_ptr 关联的完成处理程序从未被调用?
【问题讨论】:
标签: c++ windows winapi boost boost-asio