在C中有睡眠()的替代方案吗?

Man*_*bts 14 c sleep delay

在传统的嵌入式编程中,我们将提供如下的延迟函数:

for(i=0;i<255;i++)
   for(j=0;j<255;j++);
Run Code Online (Sandbox Code Playgroud)

在微处理器的视图中,这是sleep()函数的工作原理吗?

C中的sleep()函数有替代方法吗?

Chr*_*ung 25

您描述的循环类型称为"忙等待".在实际操作系统中,睡眠不会导致繁忙的等待; 它告诉操作系统在睡眠期结束之前不安排进程.


Ada*_*iss 22

一种常见的机制是使用select()保证超时的,并将睡眠时间指定为超时:

// Sleep for 1.5 sec
struct timeval tv;
tv.tv_sec = 1;
tv.tv_usec = 500000;
select(0, NULL, NULL, NULL, &tv);
Run Code Online (Sandbox Code Playgroud)

select()通常用来检查组文件描述符,等待至少一个已准备好执行I/O.如果没有准备好(或者,在这种情况下,如果没有指定fds),它将超时.

select()繁忙循环的优点在于它在休眠时消耗的资源非常少,而繁忙的循环则在处理器的优先级允许的范围内独占.


Mic*_*hne 12

替代方案取决于您尝试做什么以及您使用的操作系统.

如果你只是想浪费时间,那么这些可能会有所帮助:

在大多数unix类型的系统中,你会发现一个'usleep'功能,它或多或少像睡眠一样具有更高的分辨率.小心那个,因为它通常只能睡一个微秒.

在某些unix类型系统上,select系统调用可以与所有文件描述符集零一起使用,以便获得相当准确的亚秒等待.

在Windows系统上,你有睡眠,这几乎是相同的,但需要花费几毫秒.

在多任务操作系统中,睡眠功能有时可以作为参数给出0.这通常会导致函数放弃它的时间片,但如果没有其他任务准备好运行,则可以立即重新调度.


Lou*_*arg 12

您不会使用您发布的代码在嵌入式系统上休眠.一个不错的编译器会完全删除它,即使你的编译器没有删除它也是次优的,因为在紧密循环中运行处理器会烧毁功率,这对嵌入式系统来说是一个问题.即使没有使用电池运行的系统也会关注电源使用,因为较低的电源使用意味着更便宜的电源和冷却.

通常这样做的方法是CPU将实现某种IDLE或SLEEP指令,这将导致它暂时停止处理命令.连接到定时器电路的外部中断线将定期唤醒处理器,并且CPU检查它是否已经睡眠足够长时间,如果没有,它会重新进入休眠状态.

//Pseudo code
int start = getTime();
int end = start + sleepTime;

while (getTime() < end) {
       asm("SLEEP");
}
Run Code Online (Sandbox Code Playgroud)

具体细节因处理器而异.如果您在OS上作为进程运行,则sleep调用通常只是告诉调度程序暂停您的进程,然后内核决定是安排另一个进程还是休眠CPU.此外,上述代码不适用于需要截止日期保证等的实时系统.在这些情况下,您需要在循环中获取时间,知道时间中断的持续时间,因此您知道是否可以在没有吹过截止日期,并可能重新编程定时器硬件或忙等待.


Ton*_*les 7

你在OP中讨论"嵌入式编程".如果您正在进行嵌入式工作并需要像sleep()这样的东西,通常会有硬件计数器/计时器.这将因架构而异,因此请查看数据表.

如果你没有做嵌入式工作,我道歉:)


pax*_*blo 6

如果您正在使用for循环,那么您最好知道它们编译到什么以及这些指令以给定的时钟速度运行多长时间,确保CPU运行您的指令而不执行任何其他操作(这可以在嵌入式系统中完成,但它是因为它不允许中断而很棘手).

否则,您将无法确定实际需要多长时间.

早期的PC游戏存在这个问题 - 它们是为4.7MHz的PC而构建的,当更快的计算机出现时,它们无法播放.

"睡眠"可以起作用的最佳方式是让CPU知道在任何给定点的时间.不一定是实际时间(早上7:15),但至少是相对时间(自某个时间点起8612秒).

这样,它可以将delta应用于当前时间并在循环中等待,直到达到当前的+ delta.

任何依赖于CPU周期数的东西本质上都是不可靠的,因为CPU可能会转到另一个任务并让你的循环挂起.

假设您有一个内存映射的16位I/O端口,CPU每秒递增一次.我们还假设它位于嵌入式系统的内存位置0x33,其中整数也是16位.一个名为sleep的函数变为类似于:

void sleep (unsigned int delay) {
    unsigned int target = peek(0x33) + delay;
    while (peek(0x33) != target);
}
Run Code Online (Sandbox Code Playgroud)

你必须确保peek()每次返回内存内容(因此优化编译器不会破坏逻辑)并且你的while语句每秒运行多次,所以你不会错过目标,但这些是运营问题,不影响我提出的概念.

  • 我想你会喜欢`while(peek(0x33)<target);`,或者当你(出于某种原因)HW跳过你感兴趣的确切值时,你会有一个有趣的调试体验. (2认同)

bog*_*bog 6

有关sleep()如何在这里工作的更多信息

顺便说一下,忙碌的等待并不一定是业余爱好者 - 虽然它会烧掉您可能想要用于其他目的的处理器.如果您使用的是时间源,则仅限于该源的粒度.EG如果你有一个1毫秒的计时器,并想要500美元,你有一个问题.如果您的嵌入式系统可以处理您将在500 uSec的循环中进行嗡嗡声的事实,那么这可能是可以接受的.即使你有一个具有所需粒度的计时器,你还需要在正确的时间从该计时器中断一个...然后调度中断处理程序...然后转到你的代码.有时繁忙的循环是最方便的解决方案. 有时.


Ana*_*tts 5

忙碌等待即使在嵌入式系统中也是业余爱好者,使用实时源.


Sco*_*den 5

任何体面的 C 编译器都会在没有额外工作的情况下完全删除您的代码并且延迟会消失

  • 我记得很多年前的一些基准测试,其中一个特定的编译器生成的可执行文件在许多数量级上优于其他编译器。原来是编译器意识到循环的结果没有在其他任何地方使用,所以它优化了整个循环不存在:-)。 (4认同)