我需要在程序中等待很短的时间间隔,但是我真的不想仅使用unistd.h就包含sleep,所以我这样做是这样的:

int main()
{
for(int i=0; i<=100000000000; i++); // <----- note that the loop doesn't do anything 
return 0;
}


当我没有特别的睡眠时间间隔时,我会这样做。

这有什么问题吗?

在CI中知道如果我确实包含unistd.h,并且如果我使用sleep(),那么下面的代码也会使程序等待一小段时间:

int main()
{
sleep(2000); //or whatever the number (in milliseconds)
return 0;
}


评论

另请参阅“忙碌等待”与“睡眠”之间的权衡是什么?

您是否有不想输入“ #include ”的任何实际原因?

将100000000000用于int并不是可移植的,某些编译器不喜欢它。

我用一个程序做了同样的事情,它几乎杀死了计算机。在内部,睡眠将减轻程序的负担,并使其真正进入睡眠状态。

您撰写时可能会对其进行优化:stackoverflow.com/questions/7083482/…

#1 楼

使用for循环执行此操作的最大问题是浪费CPU功率。 )执行程序。这意味着在程序等待时,CPU将能够运行其他有有意义工作要做的程序。出于什么目的?没有。但是CPU不知道。它被告知要增加变量,这就是它的作用。同时,由于您的程序占用时间,其他程序没有太多的时间来做它们的工作。 />如评论中所述,此外,编译器可能会优化出一个空循环,并且可能会丢失暂停的尝试。因此,要么浪费CPU资源,要么根本不会暂停。

评论


\ $ \ begingroup \ $
此外,编译器可能会优化出一个空循环,并且可能会丢失暂停的尝试
\ $ \ endgroup \ $
–atk
2014年2月22日在19:45

\ $ \ begingroup \ $
此外,如果编译器将其保留下来,那么对于调度将是不利的,因为调度程序会看到一个漫长而活跃的进程。
\ $ \ endgroup \ $
– OJFord
2014年2月22日在23:08

#2 楼

过去,家用计算机曾经有一个“ turbo”按钮,(激活后)该按钮会使处理器变慢。问题在于,游戏是围绕输入循环进行编码的,该输入循环预计将花费特定的毫秒数。如果循环执行得更快,整个游戏将会加速,变得无法玩了。一秒钟?半年?)。此外,编译器通常可以自由地删除不执行任何操作的代码-在-O3下编译您的代码片段有望删除该循环。做对了–认为自己是代码工匠,而不是代码猴子(没有冒犯,rolfl)。

评论


\ $ \ begingroup \ $
没有冒犯... ;-)
\ $ \ endgroup \ $
–rolfl
2014-2-22在18:37

\ $ \ begingroup \ $
嗯,我的计算机是最新的,并且有一个Turbo按钮。但是它的行为有所不同,它在GPU上进行了软超频。
\ $ \ endgroup \ $
–皮埃尔·卢克·皮诺(Pierre-Luc Pineault)
2014年2月23日下午5:46

#3 楼

这称为“忙碌等待”或“旋转”,它可以工作,但具有以下缺点:


它将对您的程序执行“工作”,而不是将控制权交给操作系统和其他程序-因此不会与他人“玩得开心”;在普通计算机上,有许多同时运行的程序也可能希望使用该CPU。
繁忙等待会在CPU上产生不必要的负载,从而防止其空转-这会产生额外的热量,风扇噪音并降低电池电量
延迟是无法预料的-延迟会因计算机和编译器的不同而有很大差异,如其他答案所述,延迟可能会“优化”到完全没有延迟。
/>
简而言之-它会起作用,因此,如果它是一次性脚本供您自己使用,则可以,但如果它是供生产使用的代码或将来需要维护的代码,那就不要这样。

评论


\ $ \ begingroup \ $
+1提到了电池影响,这是一个相对重要的问题,这几天在移动设备上进行了大量计算。
\ $ \ endgroup \ $
– Barmar
2014年2月23日下午3:26

#4 楼

此技术称为自旋锁或繁忙等待。例如,它是在Oracle数据库软件中实现的,以协调对不同进程(闩锁)之间的内存结构的访问。旋转时的CPU时间。如果预期的等待时间很短,就是这种情况。非常短意味着您需要一些时钟周期,并且远远少于您在示例中使用的2000 ms。

如果正确实现,编译器将无法优化循环。这个使用volatile变量的C示例来自繁忙等待。

...
volatile int i=0;
...
while (i==0);
...


volatile告诉编译器,可以从当前线程外部更改变量i的值,因此编译器不会丢弃while -loop。

繁忙等待在此处被列为反模式。因此,如果您不完全了解它的后果,则不要使用它。

试图避免包含unistd.h似乎不是使用繁忙等待的有效理由。

#5 楼

此处的其他答案将解决循环中的特定问题,并希望已使您确信这不是正确的方法。我想评论一下你的动机。

为什么要避免unistd.h?仅包含一个函数的标头是完全合理的,并且在大多数情况下,没有令人信服的理由不这样做。

如果您担心可移植性,请执行以下操作:

#if defined(__linux__)
#  include <unistd.h>
#elif defined(_WIN32)
#  include <windows.h>
#  define sleep(s) Sleep((s)*1000)
#endif


然后到处使用sleep(seconds)

#6 楼

这是一个不好的主意的两个主要原因:




在给定循环上花费的时间非常依赖于运行它的计算机。曾经在现代计算机上玩过Quake吗?帧速率是通过屋顶的,我希望这并不奇怪。功能更强大的计算机可以在设定的时间内执行更多的计算。如果您的计算机需要10秒才能完成一个循环,那么功能更强大的计算机可能会在5秒钟或更短时间内完成,而较旧的计算机可能会花费更长的时间。是的,那可以确保花费相同的时间来完成该功能。但是不要太兴奋;我说了两个主要原因。

睡眠功能将线程设置为“请勿打扰”状态,从而使操作系统可以执行其他任务(处理其他线程,清理线程)。线程),而您的线程在做白日梦。虽然人们可以看着这条线并将其解释为“不执行任何操作”,但您的计算机正在浪费功率,使其以最快的速度穿越该空循环。 />
#include <Mmsystem.h> //timeGetTime
void Stall(unsigned long ms)
{
    unsigned long start = timeGetTime();
    unsigned long passed = 0;
    while (passed < ms)
    passed = timeGetTime() - start;
}


更好,但是在不必要时它仍然浪费CPU资源。而且,如果没有其他线程在运行,则Sleep(0)立即返回您的线程,这意味着您的CPU仍在以最大速度运行。 br />

#7 楼

除了占用处理器周期之外,此方法最大的单一问题是,如果在编译器中启用了任何级别的优化,则优化器都会删除for循环。突然,您发现在调试模式下可以正常运行的代码停止工作。

评论


\ $ \ begingroup \ $
反对该技术的使用并不是一个有效的论点。如果精心编程,则可以避免此问题。这是关于在使用gcc时避免对一段代码进行优化的讨论:stackoverflow.com/questions/2219829/…帮助
\ $ \ endgroup \ $
– miracle173
2014年2月23日在22:02



#8 楼

避免仅仅因为不愿意包含.h文件而调用某些适当的OS API函数并不是一个公平的权衡。这取决于您是否希望等待某些事件发生,例如通过套接字完成文件写入或数据发送。在这种情况下,最好调用仅等待事件发生的OS API。如果您只需要等待一定的时间,则还取决于您需要等待多长时间。如果您需要等待多达约5万个CPU周期,则可以结合使用PAUSE和RDTSC指令,在调用PAUSE约500次之后,调用RDTSC一次。如果需要的延迟时间超过5万个CPU周期,请创建一个可等待的高分辨率计时器,然后等待它。对于Windows,有一个函数CreateWaitableTimer。您可以在https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms687008(v=vs.85).aspx

中找到示例,如果需要在以下位置等待至少1毫秒或更长时间,您可以只调用Sleep()。但是请确保使用至少1毫秒的参数调用sleep,不要调用Sleep(0),因为它在等待时不会让CPU处于休眠状态。