我真的很荒谬。在我进行C ++编程时,需要等待很长时间。因此,我决定使用while(){...}
。
模式1::如果我使用while (1) {...}
,
CPU将承受最大的负载。 (它占用一个CPU的最大负载。)
模式2:
while(GetMessage(&msg, NULL, 0, 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
将减轻CPU的负担。
但是,while(1){...}
和while(GetMessage(&msg, NULL, 0, 0)){...}
之间的语句执行存在很大差异。
例如
模式1
dwEndTime = time(NULL) + 120;
while(1)
{
if(IsOutOfTime())
break;
}
和
模式2
dwEndTime = time(NULL) + 120;
while(GetMessage(&msg, NULL, 0, 0)
{
if(IsOutOfTime())
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
IsOutOfTime()
的实现:
BOOL IsOutOfTime()
{
if(time(NULL) >= dwEndTime)
return TRUE;
return FALSE;
}
导致不同的执行结果。 break
在模式2 下不起作用。
请有人帮我解决这个问题。
如果我在Sleep(...)
中输入while (1) {...}
,则可以减少CPU负载,但是我讨厌这样的编码样式。
1。。模式1 和模式2 之间有哪些内在区别。
2。。我是否滥用了模式2 ?
3。。如何不使用sleep
来减少CPU负载。
答案 0 :(得分:3)
如果可能,应避免同时使用模式1和2,因为两者都会轮询以检查您是否没时间。
模式1占用100%的cpu,不会处理任何Windows消息。
模式2仅在收到消息时检查超时,因此它可能会错过一段时间的超时。
相反,您应该研究使用timer的方法,该方法会在时间不足时触发。计时器到期后,GetMessage
将返回一条WM_TIMER
消息。 (我假设IsOutOfTime
只是检查是否已经过去了一段时间。)
答案 1 :(得分:2)
WinAPI包含一些允许等待事件的函数,WaitForSingleObject
,WaitForMultipleObject
函数(以及它们的...Ex
扩展名。这种等待不会给CPU造成压力,因为该进程是处于等待状态。
如果您有GUI程序并希望保持其响应速度,则应循环使用MsgWaitForMultipleObjects
函数。如果您需要等待一个对象,它会给出:
DWORD cr
while ((cr = MsgWaitForMultipleObjects(1, &handle, FALSE, milli_sec_timeout, QS_ALLINPUT)) {
if (cr == WAIT_OBJECT_0) {
// event has been signaled process it
break;
}
else if (cr == WAIT_OBJECT_0 + 1) {
// something has arrived in the thread event loop: process the message
GetMessage(&msg, NULL, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else if (cr == WAIT_TIMEOUT) {
// timeout has elapsed
...
}
else { // abnormal condition, see doc for more
...
}
}
答案 2 :(得分:2)
使线程等待给定时间段的最简单方法是使用Sleep()
:
Sleep(1000 * 120);
但是请注意,调用线程在睡眠时将被完全阻塞。如果在GUI线程中调用它,则GUI将被冻结,直到完成睡眠并且控制返回到GUI消息循环为止。
在这种情况下,您可以使用SetTimer()
并让GUI消息循环根据需要处理WM_TIMER
条消息。
另一种选择是改用Waitable Timer,例如:
HANDLE hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
LARGE_INTEGER liDueTime;
liDueTime.QuadPart = -10000000 * 120;
SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, FALSE);
// wait for hTimer to be signaled...
CloseHandle(hTimer);
在GUI线程中,您可以使用MsgWaitForMultipleObjects()
等待计时器发出信号,同时仍在维护GUI消息,例如:
HANDLE hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
LARGE_INTEGER liDueTime;
liDueTime.QuadPart = -10000000 * 120;
SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, FALSE);
bool keepLooping = true;
do
{
DWORD ret = MsgWaitForMultipleObjects(1, &hTimer, FALSE, INFINITE, QS_ALLINPUT);
if (ret == WAIT_OBJECT_0)
{
// timer elapsed ...
break;
}
if (ret == (WAIT_OBJECT_0 + 1))
{
MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
PostQuitMessage(msg.wParam);
keepLooping = false;
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
while (keepLooping);
CloseHandle(hTimer);
如果在等待计时器时不需要处理GUI消息,则可以改用WaitForSingleObject()
或WaitForMultipleObjects()
(取决于您是仅等待计时器,还是取决于计时器)也要等待其他对象):
HANDLE hTimer = CreateWaitableTimer(NULL, TRUE, NULL);
LARGE_INTEGER liDueTime;
liDueTime.QuadPart = -10000000 * 120;
SetWaitableTimer(hTimer, &liDueTime, 0, NULL, NULL, FALSE);
WaitForSingleObject(hTimer, INFINITE);
CloseHandle(hTimer);
答案 3 :(得分:1)
好的,因为您似乎在SetTimer()
(这似乎是这里的最佳解决方案)中苦苦挣扎,所以我将为您发布完整的源代码。真的很简单,请不要再忙于忙循环了。
注意:此代码不需要窗口,但确实需要一个事件循环(但您似乎对此没问题)。
设置:
VOID CALLBACK MyTimerProc (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
DWORD dwTimerID = SetTimer (NULL, 0, 120 * 1000, MyTimerProc); // 2 minute timeout
消息循环(请勿在此处测试超时)
MSG msg;
while (GetMessage (&msg, NULL, 0, 0)
{
TranslateMessage (&msg);
DispatchMessage (&msg);
}
计时器进程:
VOID CALLBACK MyTimerProc (HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
KillTimer (NULL, dwTimerID);
// Do whatever it is you wanted to do when your timeout elapsed
}
答案 4 :(得分:0)
我解决了我的问题。 while(GetMessage(..)){..}
已已阻止。
我在GetMessage()
中严重使用了while(...)
。
因为,如果没有消息要翻译和发送,则GetMessage
将被阻止,直到发生任何消息。
因此,我实现了这样的代码。
#define MESSAGE_NOT_OUT_OF_TIME WM_USER+1
#define MESSAGE_OUT_OF_TIME WM_USER+2
PostMessage(NULL, MESSAGE_NOT_OUT_OF_TIME, 0, 0);
while(GetMessage(&msg, NULL, 0, 0)
{
if (MESSAGE_NOT_OUT_OF_TIME == msg.message)
IsOutofTime();
if (MESSAGE_OUT_OF_TIME == msg.message)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
IsOutofTime()
的实现
VOID IsOutofTime()
{
if(dwEndTime <= time(NULL))
PostMessage(NULL, MESSAGE_OUT_OF_TIME, 0, 0);
else
PostMessage(NULL, MESSAGE_NOT_OUT_OF_TIME, 0, 0);
}
尽管CPU
的负载约为70%到80%,但我已经找到原因并解决了问题。