I am studying how to write a shell in C, and I have come across a method to use a "busy loop around the sleep function when implementing wait command". In the loop, the while(1)
loop is used. I suppose to loop unconditionally, and hence take up some processing time and space? What exactly is the purpose of a busy loop? Also, if the only objective in a lazy loop is to have an unconditional loop, then can't we use any other form of loop like for(;;)
instead of while(1)
too?
CodePudding user response:
A busy loop is a loop which purposely wastes time waiting for something to happen. Normally, you would want to avoid busy loops at all costs, as they consume CPU time doing nothing and therefore are a waste of resources, but there are rare cases in which they might be needed.
One of those cases is indeed when you need to sleep for a long amount of time and you have things like signal handlers installed that could interrupt sleeping. However, a "sleep busy loop" is hardly a busy loop at all, since almost all the time is spent sleeping.
You can build a busy loop with any loop construct you prefer, after all for
, while
, do ... while
and goto
are all interchangeable constructs in C given the appropriate control code.
Here's an example using clock_nanosleep
:
// I want to sleep for 10 seconds, but I cannot do it just with a single
// syscall as it might get interrupted, I need to continue requesting to
// sleep untill the entire 10 seconds have elapsed.
struct timespec requested = { .tv_sec = 10, .tv_nsec = 0 };
struct timespec remaining;
int err;
for (;;) {
err = clock_nanosleep(CLOCK_MONOTONIC, 0, &requested, &remaining);
if (err == 0) {
// We're done sleeping
break;
}
if (err != EINTR) {
// Some error occurred, check the value of err
// Handle err somehow
break;
}
// err == EINTR, we did not finish sleeping all the requested time
// Just keep going...
requested = remaining;
}
An actual busy loop would look something like the following, where var
is supposedly some sort of atomic variable set by somebody else (e.g. another thread):
while (var != 1);
// or equivalent
while (1) {
if (var == 1)
break;
}
Needless to say, this is the kind of loop that you want to avoid as it is continuously checking for a condition wasting CPU. A better implementation would be to use signals, pthread condition variables, semaphores, etc. There are usually plenty of different ways to avoid busy looping.
Finally, note that in the above case, as @einpoklum says in the comments, the compiler may "optimize" the entire loop body away by dropping the check for var
, unless it has some idea that it might change. A volatile
qualifier can help, but it really depends on the scenario, don't take the above code as anything other than a silly example.