Thomas White
Thomas White

Reputation: 41

Empty loop which waits for condition (busy-waiting)

I have been spending the last 20 minutes doing research on empty loops which purpose are only to wait for a condition to become true.

I have a function called "waitForLoaded" which is a thread created by CreateThread.

The function:

void waitForLoaded(){
    while(!isLoaded){
        Sleep(500); // < my question
    }
    Sleep(500); //sleep another 500ms to ensure everything is loaded.
    //continue on here
}

I am using Sleep(500) to be easy on the CPU as I believe that using either 0 or 1 would drain the processor.

I have seen in many peoples code "Sleep(0)" used and I never understood why not just no sleep at all and to do "while(condition){}.."

I can't find any solid answer on which is more CPU friendly so I am asking people here, what is the difference between busy-waiting with 0ms, 1ms or 500ms and which is more CPU friendly.

In my opinion it would be best to do at least a half sleep which is nearly unnoticeable by the user.

Upvotes: 4

Views: 15083

Answers (5)

Andry
Andry

Reputation: 2727

Busy waiting is basically related to a code which must calculate something to only lose the time. The Sleep does use OS scheduler in case if need to wait a quite long period of time which means it is not stable for period of times less than the scheduler time quant which is ~15ms for the Windows OS. This is not acceptible for example in case of a spinlock.

The most simple code what I could get is:

#include <cstdlib>

inline void noop_by_rand(int num)
{
    while (num--) rand();
}

Pros:

  • It is a builtin function with a fixed time of calculation less than the OS scheduler time quant.
  • Can be easely scaled on longer time.
  • The compiler optimization can not avoid the call or reduce the code because of external function.
  • Does rely on CPU performance instead of the time, which means it does scale with the performance of the CPU.

Cons:

  • Does not avoid the OS scheduler. If busy wait time is too long, then OS scheduler will anyway handle the thread for scheduling, which means it can lose much more time than requested.

Upvotes: 1

Jose Palma
Jose Palma

Reputation: 756

First you need to study your problem.

  • Do you need a busy wait?
  • Can you use a dispatcher?
  • Can you detect the exact moment when the data is available or the operation has finished?

I would take a look into different approaches like event file descriptor, or condition variable.

Condition variable approach:

boost::mutex::scoped_lock lock(m_mutex);
while(queue.empty() && !m_quit) {
    m_condition.wait(lock);
}    

Event File descriptor approach

m_loopFD = eventfd(0,EFD_CLOEXEC|EFD_NONBLOCK);
if(m_loopFD < 0) {
    close(m_epollFD);
    throw ...
}
struct epoll_event event;
memset(&event, 0, sizeof(struct epoll_event));
event.data.fd = m_loopFD;
event.events = EPOLLIN;
if(epoll_ctl(m_epollFD, EPOLL_CTL_ADD, m_loopFD, &event) != 0) {
    throw ...
}

Later you may have something like this

int res = epoll_wait(m_epollFD, events, MAX_EVENTS, timeout);

and to wake it up:

uint64_t value = 0x01;
write(m_loopFD, &value, sizeof(value));

Upvotes: 0

Amit
Amit

Reputation: 1885

A simple synchronization primitive around event or something similar would drain less of CPU AND your thread would hopefully get to work sooner than worst case 500 ms with your 500 ms wait.

Upvotes: 2

Drew Dormann
Drew Dormann

Reputation: 63765

If I understand your question, you are asking which is superior of these wait methods:

  • sleep(500)
  • sleep(1)
  • sleep(0)
  • // (do nothing)

If you have the time to afford a sleep(500), then the answer is "sleep(500)"

Upvotes: 1

zdan
zdan

Reputation: 29450

On windows a Sleep(0) will not spend any time sleeping, but allows the OS to relinquish the CPU to another waiting thread. It's kind of like saying "If someone is waiting in line let them go ahead, otherwise I'd like to go right away."

Upvotes: 12

Related Questions