c++ - 可等待的计时器不等待指定的时间段

标签 c++ windows winapi msdn

我正在创建一个手动等待计时器,如下所示

m_hTimer = CreateWaitableTimer(NULL, true, NULL);

在函数中使用它

HRESULT ClassA::InduceSleep(UINT32 uiMiliSeconds)
{
    if (m_hTimer)
    {
        LARGE_INTEGER liDueTime;
        liDueTime.QuadPart = (uiMiliSeconds) * (-10000) * (1LL);
        if (!SetWaitableTimer(m_hTimer, &liDueTime, 0, NULL, NULL, 0))
        {
            Log("SetWaitableTimer failed GLE[%d]", GetLastError());
            goto exit;
        }

        // Wait for the timer.

        if (WaitForSingleObject(m_hTimer, INFINITE) != WAIT_OBJECT_0)
        {
            Log("WaitForSingleObject failed GLE[%d]", GetLastError());
        }
        return S_OK;
    }
exit:    
    Sleep(uiMiliSeconds);
    return S_OK;
}

我观察到在延迟 10 秒(或 5 秒)调用 InduceSleep() 时,waitforsingleobject 立即返回 WAIT_OBJECT_0,没有任何延迟,因此计时器会立即发出信号。文档中提到 setwaitable timer 停止并重新激活计时器,因此它不应处于信号状态,而应仅在给定时间后发出信号。我在这里缺少什么?

最佳答案

这是一个简单的错误:

uiMiliSecondsUINT32 类型,即无符号类型。

这使得

(uiMiliSeconds) * (-10000)

无符号乘法即 -10000 在乘法之前转换为 unsigned。 (我同意,类型提升有时是一个棘手的话题。)

我在一个最小的样本中尝试了这个:

#include <iostream>

int main()
{
  uint32_t uiMilliseconds = 10 * 1000;
  std::cout << uiMilliseconds * -10000 << '\n';
  std::cout << (int)uiMilliseconds * -10000 << '\n';
  return 0;
}

输出:

4194967296
-100000000

Live Demo on coliru

因此,解决方案是在乘法之前简单地将 uiMiliseconds 转换为带符号的整数(就像我在第二行输出中所做的那样)。

故事的其余部分对 OP 来说可能是显而易见的。来自 MSDN 关于 SetWaitableTimer function :

lpDueTime

The time after which the state of the timer is to be set to signaled, in 100 nanosecond intervals. Use the format described by the FILETIME structure. Positive values indicate absolute time. Be sure to use a UTC-based absolute time, as the system uses UTC-based time internally. Negative values indicate relative time.

所以,错误的计算时间似乎产生了一个已经过去的值。这是为什么 SetWaitableTimer(m_hTimer, &liDueTime, 0, NULL, NULL, 0) 立即返回的唯一合理解释。 (OP 检查错误但没有识别出错误。)


为了让它“防弹”,我建议

 uiMiliSeconds * -10000LL

考虑到例如VC 为 int 使用 32 位(即使对于 x64)。因此,由于类型提升,任何 UINT32 值都将扩展为相应的 long long 而没有溢出的危险。


RbMm 提示 MiliSeconds 类型 UINT32 可能是一个不太幸运的选择,因为它只涵盖了可以设置的时间子范围。在 OP 的情况下,这个子范围可能就足够了。否则,可能会考虑类型 UINT64

关于c++ - 可等待的计时器不等待指定的时间段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54800096/

相关文章:

c++ - 基本 C++(我认为是 cout 缓冲区还是溢出?!)

c++ - 问题 - TCHAR 作为 LPARAM 到属于另一个进程/线程的窗口

.net - Powershell 和 winapi SystemParametersInfo 函数

c++ - winsock 和 QTcpServer 之间的套接字交换

c++ - 在 Windows 上部署 Qt 5 应用程序

c++ - 根据 if 语句初始化对象

c++ - 如何将 DLL 注入(inject) Delphi 程序

c - 读写互斥

c++ - 为什么这段代码用 g++ 而不是 MSVC++ 编译?

c++ - 如何通过矩阵的上三角形压平循环?