【问题标题】:What is the cleanest way to create a timeout for a while loop?为while循环创建超时的最干净的方法是什么?
【发布时间】:2011-01-09 07:25:11
【问题描述】:

Windows API/C/C++

1. ....  
2. ....
3. ....    
4.    while (flag1 != flag2)
5.    {
6.      SleepEx(100,FALSE);   
        //waiting for flags to be equal (flags are set from another thread).
7.    }
8. .....
9. .....  

如果标志在 7 秒后不相等,我想继续第 8 行。

感谢任何帮助。谢谢。

【问题讨论】:

  • 在你摆脱繁忙循环后,将超时传递给你的代码将包含的等待函数。
  • 在一个结合了数据驱动和定时器驱动中断的嵌入式环境中...... C / C++ 是相当低级的。我想知道你是否也可以这样做。
  • 是的。在 Windows 中,它的 API 是 WaitForSingleObject() 和朋友。
  • 更不用说,您没有使用联锁操作来检查这两个字段会导致麻烦

标签: c++ c windows algorithm winapi


【解决方案1】:

您可以使用 WinAPI 中的QueryPerformanceCounter。在开始之前检查它,并查询是否经过了时间。然而,这是一个高分辨率定时器。对于较低的分辨率,请使用 GetTickCount(毫秒)。

一切都取决于您是主动等待(做某事)还是被动等待外部进程。如果是后者,那么下面使用Sleep的代码会容易很多:

int count = 0;
while ( flag1 != flag2 && count < 700 )
{
   Sleep( 10 ); // wait 10ms
   ++count;
}

如果您不使用 Sleep(或 Yield)并且您的应用不断检查某个条件,那么您将导致应用运行的 CPU 膨胀。

如果你广泛使用 WinAPI,你应该尝试更原生的解决方案,阅读 WinAPI 的Synchronization Functions

【讨论】:

  • 您忘记在循环内增加计数 XD
  • 请注意,您的解决方案并不那么精确。指定 10ms 的睡眠意味着睡眠可能约为 10 毫秒。这取决于底层的计时器分辨率。此外,如果还有其他繁忙的更高优先级线程处于活动状态,您可能需要等待更长的时间,因此您不能依赖 10 毫秒的睡眠实际上是 10 毫秒。
  • @zdan - 我怀疑 OP 想要一个精确的解决方案。如果他真的想要精确的话,他可以使用 QPC - 并且至少没有 Sleep(1) 他会消耗资源。
【解决方案2】:

确保在其中执行 sleep()yield(),否则您将耗尽所有等待的 CPU(或内核)。

【讨论】:

    【解决方案3】:

    如果您正在等待设置特定标志或达到某个时间,更简洁的解决方案可能是使用自动/手动重置事件。这些是为线程之间的信号条件而设计的,并且在它们之上设计了非常丰富的 API。例如,您可以使用采用显式超时值的 WaitForMultipleObjects API。

    【讨论】:

      【解决方案4】:

      不要轮询更改标志。即使在循环期间睡眠或让步,这也只会浪费 CPU 周期。

      取而代之的是,获取设置标志的线程来通知您它们已被更改,可能使用event。您对事件的等待需要超时,您可以调整以允许总共等待 7 秒。

      例如:

      Thread1:
      
       flag1 = foo;
       SetEvent(hEvent);
      
      
       Thread2:
      
       DWORD timeOutTotal = 7000;  // 7 second timeout to start.
       while (flag1 != flag2 && timeOutTotal > 0)
       {
           // Wait for flags to change
           DWORD start = GetTickCount();
      
           WaitForSingleObject(hEvent, timeOutTotal);
      
           DWORD end = GetTickCount();
      
          // Don't let timeOutTotal accidently dip below 0.
          if ((end - start) > timeOutTotal)
          {
              timeOutTotal = 0;
          }
          else
          {
             timeOutTotal -= (end - start);
          }
      
       }
      

      【讨论】:

        【解决方案5】:

        你没有提到如果标志相等会发生什么。

        另外,如果你只是在没有内存屏障的情况下测试它们,那么你不能保证看到其他线程进行的任何写入。

        最好的办法是使用事件,并使用具有 7000 毫秒超时的 WaitForSingleObject 函数。

        【讨论】:

          【解决方案6】:

          如果您的应用程序做了一些网络工作,请查看 POSIX select() 调用,尤其是超时功能!

          【讨论】:

          • 我建议查看“民意调查”或“选择”(老派)。阅读精彩的 Beej Networking 指南,了解如何同时使用两者及其区别:beej.us/guide/bgnet
          【解决方案7】:

          我会说“检查时间,如果 7 秒后没有发生任何事情,则中断循环。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-12-21
            • 1970-01-01
            • 1970-01-01
            • 2019-12-19
            • 2014-05-03
            • 1970-01-01
            • 2010-10-08
            相关资源
            最近更新 更多