没有 100% cpu 的 C 主循环
Posted
技术标签:
【中文标题】没有 100% cpu 的 C 主循环【英文标题】:C Main Loop without 100% cpu 【发布时间】:2010-11-16 09:25:35 【问题描述】:#include <stdio.h>
int main()
while(!DONE)
/* check for stuff */
return 0;
上述代码示例使用 100% cpu 直到 DONE 为真。如何实现一个循环并仅在 DONE 时终止但不使用 100% cpu 的程序? 现代语言使用 App.ProcessMessages 之类的东西来让操作系统暂时控制,然后返回循环。
我是 C 的新手,显然...使用最新的 GCC、linux 和 windows(便携式解决方案会很棒!)
【问题讨论】:
您应该使用同步对象,您可以等待它发出信号,这样您根本不会消耗 CPU。 什么是DONE
,什么会导致它不为零?大概在“检查东西”评估将 DONE 设置为非零的东西之前继续处理是有意义的?
Lasse V. Karlsen:您的解决方案似乎很有意义(它可能确实很有意义,但我只是没有这些知识)。你能详细说明一下吗?我应该调查线程吗? (一个很好的例子) Charles Bailey:DONE 应该是一个 int(完成而不是 DONE),例如,当用户选择退出应用程序时,它会设置为 1。如果我不能很好地解释自己,我很抱歉..
您不需要使用任何与线程相关的东西来使单线程应用程序不忙于等待。你能告诉我们(通常,甚至)代码在循环中做了什么吗?您似乎暗示它将接受用户输入。这本身应该会导致它花费大量时间等待而不是消耗 CPU。
如果“用户输入”是您正在等待的唯一项目,那么您应该对正在使用的任何用户输入方法使用阻塞读取。在获得明智的答案之前,您需要提供有关您的程序的更多详细信息。特别是,如果您只需要一个阻塞调用(例如getchar()
),线程和同步对象就会复杂得多。
【参考方案1】:
这取决于你想在这个循环中做什么。
如果您在循环内等待(即如果按键 做某事 那么您的机制将浪费系统资源而没有任何回报。更快的处理器只会产生更多的空闲循环。这可以通过等待事件来解决 而不仅仅是睡眠,但最好是触发可以完成有意义的事情的事件。例如,文件操作(stdin 也是文件)将是一种可移植机制。这将让位于其他应用程序,直到数据可用。当你变得更具体来说,可能需要深入研究通常依赖于操作系统的信号量或信号。抽象层可以解决这个问题。
如果您正在做一些有用的事情(即处理大量数据),那么 100% cpu 负载仅意味着处理器以最有效的方式使用。您可以依靠操作系统让位于其他可能更高优先级的任务。
使用睡眠之类的功能会降低 CPU 使用率,但您的应用程序会变慢。它将需要在可接受的性能和 cpu 负载之间进行权衡。最大执行速度将由您的 sleep 参数定义,而不再由 cpu 速度定义。此外,如果电源是一个问题(即电池寿命),那么这将需要 CPU 唤醒(睡眠期结束)而无需做任何工作;即不同的系统资源浪费。
【讨论】:
我想我必须学习信号量和信号然后有什么具体的指针吗? :) 主循环里面有什么样的处理?消息、信号、信号量与操作系统的关系比与底层语言的关系更大。例如,ibm.com/developerworks/eserver/library/es-win32linux-sem.html 显示了信号量在 windows 和 linux 中的处理方式。如果您需要同时支持两者,您可以使用 POSIX(对于 windows 是可选的,即在 cygwin 中)或将代码放在您为每个操作系统创建的平台相关模块中。【参考方案2】:您有多种选择:
-
使用 sleep() 强制进程定期挂起并允许其他进程使用 CPU
以较低的优先级运行 - 这将导致操作系统分配更少的 CPU 时间
使用互斥锁或其他同步对象来检测工作何时可用 - 这将防止进程消耗任何 CPU 时间,除非它确实在工作
如果您的工作比您处理它的速度快 - 您可能仍需要使用某种睡眠/优先级模型以避免完全消耗 CPU。
以平台/操作系统中立的方式执行选项 #2 可能会很棘手。最好的办法是启动进程并在运行时环境中更改其优先级。
【讨论】:
【参考方案3】:您的两个选项是轮询和某种事件通知。
轮询是最容易编程的——基本上你的线程在每次通过循环时都会休眠一小会儿。这会将处理器释放到其他任务。缺点是你的“检查东西”代码会有延迟——所以如果你睡了一秒钟,你的代码可能需要一秒钟才能检测到这种情况。您在此处的代码将很容易移植。
另一种选择是等待 POSIX 条件或 Windows 事件或类似事件。不仅会更改此代码,而且“您正在检查的内容”将需要触发标志以表示已完成。尽管可能有库可以抽象出平台,但这将是可移植性较差的代码。但是您会立即获得事件的结果,并且不会浪费处理器时间检查不存在的内容。
【讨论】:
【参考方案4】:你到底在检查什么?
如果您正在检查由硬件或其他进程更改的易失性内容,只需在循环中调用 sleep
。
如果您正在等待文件描述符或网络套接字描述符,您将需要在循环中使用 select
或 poll
来等待描述符准备好数据以供使用。
【讨论】:
【参考方案5】:如果我理解正确,您在 cmets 中说过 DONE 可以从其他线程更改。如果是这样,条件变量是有意义的。使用 pthreads,可以这样做:
在等待的线程中:
pthread_mutex_lock(&mutex);
while (!DONE)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
在其他线程中,当 DONE 发生变化时:
pthread_mutex_lock(&mutex);
DONE = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
【讨论】:
【参考方案6】:Sleep(0);
我猜就够了
【讨论】:
【参考方案7】:使用
睡眠(int 毫秒)
【讨论】:
睡眠的参数实际上是秒数,而不是毫秒。 我认为这实际上取决于操作系统...虽然您对 Unix/Linux/*BSD 下的参数是秒是正确的,但我想我记得在 Windows 下它是毫秒...不过已经好几年了,所以我可能是错的...... sleep() 需要几秒钟。 usleep() (BSD 和 POSIX)需要几微秒。 nanosleep()(也是 POSIX)需要纳秒。 睡眠应该是最后的手段,因为即使没有工作要做,它也会唤醒处理器。这可能会破坏笔记本电脑等设备上的电源管理。【参考方案8】:使用yield()。
【讨论】:
这是不可移植的,因为它既不是由 C 标准也不是 POSIX 定义的。 这不是给其他进程更多时间,仍然占用其他进程不消耗的所有时间吗?【参考方案9】:如果我猜对了(我不知道),相当于 App.ProcessMessages 正在做阻塞 IO。而且由于我不知道在使用轮询的多任务操作系统上的任何 C 实现,因此任何标准 C IO 都应该是安全的。
【讨论】:
【参考方案10】:在 windows 上,您可以使用在 windows.h 中定义的 Sleep(int milliseconds)。
【讨论】:
【参考方案11】:睡眠(0);够了
【讨论】:
以上是关于没有 100% cpu 的 C 主循环的主要内容,如果未能解决你的问题,请参考以下文章