【问题标题】:Does using Sleep() in the timer callback function can cause problems in C++?在定时器回调函数中使用 Sleep() 会导致 C++ 出现问题吗?
【发布时间】:2019-01-17 03:06:26
【问题描述】:

我有一个关于计时器和睡眠的问题。我正在使用 MFC 创建一个 UI,并为 200 毫秒的特定对话框设置了一个计时器。因此每 200 毫秒调用一次 OnTimer 函数。在这个函数中,我包含了函数 Sleep(50)。所以这里将简化代码。

BEGIN_MESSAGE_MAP(MainDialog, CDialog)
  ...
  ON_WM_TIMER()
  ...
END_MESSAGE_MAP()

BOOL MainDialog::OnInitDialog() {
   ...
   SetTimer(1, 200, NULL);
   ...
}

void MainDialog::OnTimer(UINT nIDEvent) {
  ...
  Sleep(50)
  ...
}

那么这段代码会导致任何潜在的问题或麻烦吗?并且与睡眠功能一样,OnTimer 将在整个执行 OnTimer 后 150 毫秒或执行 OnTimer 功能后 200 毫秒后再次调用。我问这个是因为我的代码包含一个错误,并且想知道这是否是它的来源。提前感谢您的宝贵帮助。

【问题讨论】:

  • 这听起来很傻。你为什么要这样做——它应该解决什么问题?如果 UI 线程准备好生成事件,计时器将(大约)每 200 毫秒触发一次,无论睡眠状态如何。
  • 为简化起见,我需要将数据写入 USB 设备,而这个设备会回复我所需的数据。读取和写入在两个不同的线程中完成,并将数据存储在全局缓冲区中,因此我大约等待 50 毫秒,然后将来自设备的答案存储在缓冲区中,并且此数据对于计时器函数中的下一个任务是必需的。我可能可以用另一种方式做到这一点,但想知道这种行为是否会延迟下一次计时器中断或会产生其他影响。
  • 当 UI 可以更新时,从其他线程向您的 UI 发送消息,不要在 UI 消息处理程序中休眠。
  • "读取和写入在两个不同的线程中完成,并将数据存储在全局缓冲区中,因此我大约等待 50 毫秒,然后将设备中的答案存储在缓冲区中,这个数据是计时器功能中的下一个任务所必需的“ -​​ 不要使用睡眠来协调这样的操作。改用可等待同步,例如事件、条件变量等。这是典型的生产者/消费者情况,有很多可行的解决方案可以随时处理。

标签: c++ user-interface mfc


【解决方案1】:

1) GUI 中的 sleep 命令,在你的情况下是一个对话框,会使你的界面变得迟缓,所以避免使用它。

2) 在您的情况下,OnTimer 成员函数将大约每 200 毫秒时钟滴答被调用一次。但是,如果 OnTimer() 函数的执行时间超过 200 毫秒,就会在之前的调用完成后立即再次调用定时器,从而导致错误计时。

3) OnTimer() 对于时间要求严格的工作不准确,请改用基于 std::chrono::high_resolution_clock 的方法。

【讨论】:

  • "但是,如果 OnTimer() 函数的执行时间超过 200ms,定时器会在之前的调用完成之前再次调用,导致计时错误。" - 那不是真的。当计时器经过时,操作系统只是在消息队列中发出一个标志信号,直到消息队列被抽出并且没有其他更高优先级的消息处于挂起状态时,才会生成相应的WM_TIMER 消息。所以OnTimer 不会被再次调用,直到OnTimer 退出并且执行流程返回到消息循环。除非您的 OnTimer 代码将消息队列泵入新消息(它不应该这样做)。
  • 另外,system_clock 是在需要正确计时时使用的错误时钟。不保证稳定,可以随时调整。相反,请使用 high_resolution_clocksteady_clock
  • @RemyLebeau:谢谢。已编辑
  • @IInspectable:已编辑。谢谢
猜你喜欢
  • 2016-06-16
  • 1970-01-01
  • 2021-12-12
  • 2014-12-26
  • 2017-07-17
  • 1970-01-01
  • 1970-01-01
  • 2020-04-25
  • 1970-01-01
相关资源
最近更新 更多