while循环总是占用CPU的全部用量吗?

时间:2012-01-01 08:31:55

标签: c++ c timer operating-system

我需要创建一个服务器端游戏循环,问题是如何限制循环cpu的使用。

根据我的编程经验,繁忙的循环总是占用最大的CPU使用率。但我正在阅读SDL(Simple DirectMedia Layer)的代码,它有一个函数SDL_Delay(UINT32 ms),并且它有一个while循环,它是否需要最大cpu使用,如果没有,为什么?

https://github.com/eddieringle/SDL/blob/master/src/timer/unix/SDL_systimer.c#L137-158

do {
    errno = 0;

#if HAVE_NANOSLEEP
    tv.tv_sec = elapsed.tv_sec;
    tv.tv_nsec = elapsed.tv_nsec;
    was_error = nanosleep(&tv, &elapsed);
#else
    /* Calculate the time interval left (in case of interrupt) */
    now = SDL_GetTicks();
    elapsed = (now - then);
    then = now;
    if (elapsed >= ms) {
        break;
    }
    ms -= elapsed;
    tv.tv_sec = ms / 1000;
    tv.tv_usec = (ms % 1000) * 1000;

    was_error = select(0, NULL, NULL, NULL, &tv);
#endif /* HAVE_NANOSLEEP */
} while (was_error && (errno == EINTR));

3 个答案:

答案 0 :(得分:3)

该循环不会占用所有CPU。它利用两个不同函数中的一个来告诉操作系统暂停线程一段给定的时间并让另一个线程利用CPU:

// First function call - if HAVE_NANOSLEEP is defined.
was_error = nanosleep(&tv, &elapsed);

// Second function call - fallback without nanosleep.
was_error = select(0, NULL, NULL, NULL, &tv);

答案 1 :(得分:3)

此代码使用select进行超时。 select通常采用文件描述符,并使调用者等待直到fd上发生IO事件。它还需要一个超时参数来等待最长时间。这里fd为0,因此不会发生任何事件,并且在达到超时时函数将始终返回。

您从C库获得的select(3)select(2)系统调用的包装器,这意味着调用select(3)最终会让您进入内核。然后,除非发生IO事件或达到超时,否则内核不会调度该进程。所以这个过程在等待时没有使用CPU。

显然,跳入内核和进程调度会引入延迟。因此,如果您必须具有非常低的延迟(纳秒),则应该使用忙等待。

答案 2 :(得分:1)

当线程在SDL_Delay中被阻塞时,它会将CPU产生到其他任务。如果延迟足够长,操作系统甚至会在没有其他工作要做的情况下将CPU置于空闲或暂停模式。请注意,如果延迟时间不是至少20毫秒左右,这将无法正常工作。

然而,这通常不是你正在尝试做的任何事情的正确方法。你的外在问题是什么?为什么你的游戏循环在这个时候没有完成任何需要做的事情,所以需要等待一些事情发生,以便它有更多的工作要做?如何立即完成无限量的工作?