19

I'm working through a chapter about iPhone audio and have come across a section of code that I can't make sense of:

while (aqc.playPtr < aqc.sampleLen) 
{
    select(NULL, NULL, NULL, NULL, 1.0);
}

(Full code sample is on pages 163-166). From what I understand of the code the audio is being processed on another thread and the while loop is just there to prevent the main thread from terminating while audio is still being processed.

What I don't understand is why select() is being used instead of sleep().

From what I've read select() is used to monitor changes in I/O and passing it NULLs doesn't do anything meaningful. I've ran the code using sleep() and it works as expected. (My knowledge of low level POSIX is almost non-existant.)

Benedict Cohen
  • 11,912
  • 7
  • 55
  • 67
  • 2
    scary. I didn't know that people still use that old trick. And this on a seemingly new and shiny architecture where plenty of other means to `sleep` should be available. shame on the programmer / write of such a code. – Jens Gustedt Jun 27 '10 at 06:57
  • 8
    @JensGustedt not as scary as passing a `double` as a parameter when the function expects a **pointer** to a `struct timeval` – JeremyP Jun 06 '12 at 13:31
  • @JensGustedt This is actually a very safe way of sleeping, because sleep() may not work e.g. in a signal handler. – LubosD Sep 06 '17 at 17:16
  • 3
    @LubosD, weird that you reply to a comment from 5 years ago. Sleeping in a signal handler is not a very good idea, I think. Also `nanosleep` is in POSIX since 2001, so 16 years now. It has a well defined strategy to deal with signals, which `select` doesn't have. A POSIX system that has not yet been updated to that, belongs in the trash. – Jens Gustedt Sep 06 '17 at 21:30
  • @JensGustedt not that weird that you reply to something from 5 years ago. Some things reoccur again and again – MauriceRandomNumber Mar 04 '22 at 10:05

6 Answers6

19

Select allow for accurate sub second wait, and is more portable than sleep. There are other ways to wait, see this question.

But the timeout parameter of select should not be a float but a pointer to struct timeval. I'm surprised the code you show even compiles. More : this strange conditional select is followed by an unconditional sleep(1). Looks pointless to me.

Community
  • 1
  • 1
kriss
  • 23,497
  • 17
  • 97
  • 116
15

Using select() with NULL rfds, wfds and efds is an idiomatic way of portably sleeping with subsecond resolution.

Grijesh Chauhan
  • 57,103
  • 20
  • 141
  • 208
ninjalj
  • 42,493
  • 9
  • 106
  • 148
6

Well, sleep(3) may be implemented by using signals. It depends on the platform.

When you use select(2) and poll(2), you know that no signals will be involved, which is often very useful. For example, if you are using alarm(2), you should not use sleep(3) as well, because "mixing calls to alarm and sleep is a bad idea" (according to the man page.)

Also, select and poll give you millisecond granularity when sleeping, but sleep only has a granularity in terms of seconds.

cmccabe
  • 4,160
  • 1
  • 24
  • 10
3

When you use SIGALM signal in your application and you use (u)sleep functions, when SIGALRM occurs program immediately return from sleep function, so the best way to sleep is to wait on select function.

struct timeval tv;

tv.tv_sec = 1;
tv.tv_usec = 1000;

do
{
  ret = select(1, NULL, NULL, NULL, &tv);
}
while((ret == -1)&&(errno == EINTR)); //select is interruped too
yegorich
  • 4,653
  • 3
  • 31
  • 37
Artur
  • 31
  • 1
  • Does select adjust `tv` for the time elapsed? If not then your wait loop will restart the whole time interval at each `EINTR` occurence. – Patrick Schlüter May 27 '13 at 08:13
1

The real reason to use 'select' instead of 'sleep' is the accuracy of sleep, especially the audio or video playback. Use 'select' can get higher precision time interval for sleeping on linux or windows or other OS than 'sleep'.

I am surprised that many people actually don't know why. And please stop to shame on the programmer / write of such a code.

Yuanhui
  • 459
  • 5
  • 15
-6

There's no reason to do it. There's no reason ever to Sleep() either. One should always be expecting at least one event - program shutdown request.

Pavel Radzivilovsky
  • 18,794
  • 5
  • 57
  • 67
  • I don't see what that has to do with anything. A shutdown request will cause a `SIGTERM` which is handled by a signal handler, default or otherwise. – Matthew Flaschen Jun 26 '10 at 22:31
  • 2
    That neither answers the question, nor makes much sense... there's plenty of good reasons to sleep, especially on embedded platforms (which half-includes the iPhone, I guess) – Steven Schlansker Jun 26 '10 at 22:36
  • I agree with Pavel... there's almost never a reason to call Sleep() (except possibly as a temporary debugging measure). Any thread that is blocked in Sleep() can't be shut down cleanly until it awakes, which makes shutdown unnecessarily slow. (Having Sleep() return in response to an incoming signal is a work-around for that, but mixing signals and multiple threads is a nasty bag of worms that it's best to avoid). It's better to use an event-driven approach, and block in something that can be unblocked by an incoming event, e.g. select(). – Jeremy Friesner Sep 27 '11 at 02:50
  • This is false. On a tight event loop, where nothing is happening most of the time you can burn 100% CPU just doing nothing. Adding just a millisecond of sleep() can drop your CPU usage down to near 0% during these periods. There may be trade-offs to consider and it may be that select() or pselect() are better alternatives. But if you need polling, sleep() can be your best friend. – milesvp Sep 16 '16 at 23:23