【问题标题】:What is the purpose of WSA_WAIT_EVENT_0 in overlapped IO?重叠 IO 中 WSA_WAIT_EVENT_0 的用途是什么?
【发布时间】:2018-11-26 20:50:09
【问题描述】:

我在网络方面的所有经验都是在 Linux 上的,所以我是 Windows 网络方面的绝对初学者。这可能是一个愚蠢的问题,但我似乎无法在任何地方找到答案。考虑以下代码 sn-p:

    DWORD Index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE);
    WSAResetEvent( EventArray[Index - WSA_WAIT_EVENT_0]);

每次从 EventArray 中选择事件时,都会从索引中减去 WSA_WAIT_EVENT_0,但在 winsock2.h 中将 WSA_WAIT_EVENT_0 定义为零。

为什么代码中会出现这种看似不必要的减法?显然编译器会优化它,但仍然不明白它为什么在那里。

【问题讨论】:

  • 这样做是为了提高代码的清晰度和自记录性。 WSA_WAIT_EVENT_0 的值当然不能更改 - 在所有版本中它始终为 0

标签: c winsock2 overlapped-io


【解决方案1】:

The documentation 表示,如果事件 0 已发出信号,它将返回 WSA_WAIT_EVENT_0,如果事件 1 已发出信号,则返回 WSA_WAIT_EVENT_0 + 1,依此类推。

当然,他们在这个版本的 Windows 中将 WSA_WAIT_EVENT_0 设置为 0,但是如果在下一个版本中它是 1,或者是 100?

【讨论】:

  • WSA_WAIT_EVENT_0 不能在新版本的 Windows 中更改,因为这是破坏已经构建的二进制文件。它总是 0
  • @RbMm 它可以在不同的处理器架构上更改,如果 Windows 有某种方式可以知道它是为哪个版本构建的(例如清单),则可以更改它,如果微软突然决定他们不关心向后兼容性(例如它在 UWP 上可能有不同的价值)。您也可能正在使用某种 Windows 模拟器库来移植到 Linux(例如),这需要重新编译并且可能没有值 0(因为库作者也阅读了文档)。
  • 这当然绝对不依赖于处理器架构。如果微软突然决定不支持所有已经构建的应用程序,这些应用程序使用并硬编码这个值 - 是的,可以改变。
【解决方案2】:

WSA_WAIT_EVENT_0 定义为 0 的事实无关(它只是 WaitFor(Single|Multiple)Object(s)() API 中 WAIT_OBJECT_0 的别名,它也定义为 0 - WSAWaitForMultipleEvents() 是本身只是WaitForMultipleObjectsEx() 的包装器,尽管微软保留在不破坏现有用户代码的情况下在未来更改实现的权利。

WSAWaitForMultipleEvents()可以同时操作多个事件,其返回值将是以下几种可能之一:

WSA_WAIT_EVENT_0 .. (WSA_WAIT_EVENT_0 + cEvents - 1)

一个特定的事件对象发出信号。

WSA_WAIT_IO_COMPLETION

执行了一个或多个警报 I/O 完成例程。

WSA_WAIT_TIMEOUT

发生超时。

WSA_WAIT_FAILED

函数失败。

通常,代码应该查看返回值并采取相应措施,例如:

DWORD ReturnValue = WSAWaitForMultipleEvents(...);
if ((ReturnValue >= WSA_WAIT_EVENT_0) && (ReturnValue < (WSA_WAIT_EVENT_0 + EventTotal))
{
    DWORD Index = ReturnValue - WSA_WAIT_EVENT_0;
    // handle event at Index as needed...
}
else if (ReturnValue == WSA_WAIT_IO_COMPLETION)
{
    // handle I/O as needed...
}
else if (RetunValue == WSA_WAIT_TIMEOUT)
{
    // handle timeout as needed...
}
else
{
    // handle error as needed...
}

考虑到bAlertableFALSE(不能调用I/O 例程)和dwTimeoutWSA_INFINITE(不能超时),这可以简化,所以只有两种可能的结果- 发出事件信号或发生错误:

DWORD ReturnValue = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE);
if (ReturnValue != WSA_WAIT_FAILED)
{
    DWORD Index = ReturnValue - WSA_WAIT_EVENT_0;
    WSAResetEvent(EventArray[Index]);
}
else
{
    // handle error as needed...
}

【讨论】:

    猜你喜欢
    • 2016-10-29
    • 2012-05-06
    • 2014-08-28
    • 2017-03-01
    • 2011-02-22
    • 1970-01-01
    • 1970-01-01
    • 2012-06-03
    • 1970-01-01
    相关资源
    最近更新 更多