4

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.

Thomas White
  • 41
  • 1
  • 1
  • 3
  • "what would you personally do" is an opinion-based question, which isn't really what this site is for. – Drew Dormann Jan 15 '15 at 05:20
  • 1
    @DrewDormann you're absolutely right, I should be asking for why one is better than the other. I will change my question around. – Thomas White Jan 15 '15 at 05:21
  • `sleep(0)` at least causes a thread re-schedule. It isn't equivalent to 'no sleep at all'. How long you sleep for is up to you. The final sleep in your code is pointless. – user207421 Jan 15 '15 at 05:22
  • if your app is single threaded, calling waitForLoaded will freeze your app forever! – Maher Jan 15 '15 at 05:24
  • Actually @EJP it's required believe it or not because the function which sets "isLoaded" is not 100% accurate as you need to take system lag into consideration. The 500ms sleep at the end was required for the final build as some users experienced problems without it. Thanks for your input though. – Thomas White Jan 15 '15 at 05:24
  • 1
    @Maher of course it's not single threaded, I wouldn't be here asking the question the same way if the app froze.. Thanks for your input. – Thomas White Jan 15 '15 at 05:26

5 Answers5

10

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."

zdan
  • 28,667
  • 7
  • 60
  • 71
  • Great answer, it was made absolutely understandable and is very helpful. Thank you for answering my question. I was never exactly too sure what "thread re-scheduling" meant. – Thomas White Jan 15 '15 at 05:28
2

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.

Amit
  • 1,836
  • 15
  • 24
  • I came across "synchronization primitive" a little earlier but never got too into depth with its meaning. I will do my research, Thank you. – Thomas White Jan 15 '15 at 05:32
1

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)"

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
  • I like your answer too, it only makes sense in my eyes to sleep for as long as possible to give the CPU some sort of rest. I'll need to get a better understanding of "thread re-scheduling" so I can fully understand the benefit in using Sleep(0) that others are talking of. Thank you. – Thomas White Jan 15 '15 at 05:30
0

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));
Jose Palma
  • 756
  • 6
  • 13
0

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.
Andry
  • 2,273
  • 29
  • 28