Why isn't usleep working?

2019-07-31 10:14发布

问题:

I have a function that is being run on a separate queue/thread. In this function I am trying to call usleep.

Regardless of the value passed in, usleep doesn't seem to work. The same goes for sleep().

To diagnose the error, I printed out errno. errno prints as: "Interrupted system call"

What exactly does this mean, and how could I go about diagnosing it?

The man pages describe the error as:

[EINTR]            A signal was delivered to the process and its action was to invoke a signal-catching
                    function.

Note I am on OSX Mountain Lion using Xcode 4 and using Objective-C. I am developing an app for OSX using Cocoa.

回答1:

usleep and sleep can be interrupted in this manner by the delivery of signals.

There is no dedicated signal delivery thread, so signals can be delivered to arbitrary threads in your application.

Note Original answer left below does not work properly on Mountain Lion - something else is triggering the EINTR when run under XCode.

To avoid this problem, we swap over to nanosleep, and use the fact that when it gets interrupted it returns the remaining time in the second parameter:

struct timespec to_sleep = { 1, 0 }; // Sleep for 1 second
while ((nanosleep(&to_sleep, &to_sleep) == -1) && (errno == EINTR));

Although, if you're using an NSThread, then you're better off using:

[NSThread sleepForTimeInterval:1.0f]; // sleep for 1 second

which is the Cocoa way of sleeping, and does not suffer from the 'hiccuping' that sleep, usleep and nanosleep experience

Old Answer - Does not work properly under the debugger.

If you want to prevent the thread that has your usleep from being interrupted, you need to mask out all the signals that may be delivered to the thread. e.g.

#include <signal.h>

sigset_t sigset;
sigset_t oldset;
sigfillset(&sigset);
pthread_sigmask(SIG_BLOCK, &sigset, &oldset);
usleep(9999);
pthread_sigmask(SIG_SETMASK, &oldset, NULL);

Note: No error checking done in this code



回答2:

You can't arbitrarily print errno at any time and expect it to be useful. It is a per-thread variable that will only be set after a particular syscall sets it.

I.e. you can only check errno when you have determined that a call has failed.

It is highly unlikely that either call is failing. Exceedingly unlikely.


It wasn't clear from your question that you were grabbing the return value.

  • Try it outside the debugger, it may be the debugger hosing things w/signals. If so, it is likely a bug.

  • Do you have any other signal heavy code or subsystems in play? Signal handlers are screwy on Unix systems, in general.

  • are you using lldb? have you tried switching to gdb?