Sleeping for milliseconds on Windows, Linux, Solar

2019-01-19 13:52发布

I have to write a C program which has to sleep for milliseconds, which has to run on various platforms like Windows, Linux, Solaris, HP-UX, IBM AIX, Vxworks, and Windriver Linux

  • On Windows, the Sleep system call will work on milliseconds only.
  • On Linux, sleep will work on seconds; usleep will perform on microseconds and it's available on Solaris also.
  • In Vxworks, I hope I can implement using taskDelay and sysClkRateSet.

How can I achieve this millisecond sleep on HP-UX, IBM AIX and Wind River Linux?

3条回答
神经病院院长
2楼-- · 2019-01-19 14:16

Propably a wrapper using platform specific #defines will do:

#if defined(WIN32)
  #include <windows.h>
#elif defined(__UNIX__)
  #include <unistd.h>
#else
#endif

...

int millisleep(unsigned ms)
{
#if defined(WIN32)
  SetLastError(0);
  Sleep(ms);
  return GetLastError() ?-1 :0;
#elif defined(LINUX)
  return usleep(1000 * ms);
#else
#error ("no milli sleep available for platform")
  return -1;
#endif
}

Update

Referring to Jonathan's comment below, please find a more modern, more portable (and as well corrected :}) version here:

#if defined(WIN32)
  #include <windows.h>
#elif defined(__unix__)
  #include <time.h>
  #include <unistd.h>
#else
#endif

...

int millisleep(unsigned ms)
{
#if defined(WIN32)

  SetLastError(0);
  Sleep(ms);
  return GetLastError() ?-1 :0;

#elif _POSIX_C_SOURCE >= 199309L

  /* prefer to use nanosleep() */

  const struct timespec ts = {
    ms / 1000, /* seconds */
    (ms % 1000) * 1000 * 1000 /* nano seconds */
  };

  return nanosleep(&ts, NULL);

#elif _BSD_SOURCE || \
  (_XOPEN_SOURCE >= 500 || \
     _XOPEN_SOURCE && _XOPEN_SOURCE_EXTENDED) && \
  !(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)

  /* else fallback to obsolte usleep() */

  return usleep(1000 * ms);

#else

# error ("No millisecond sleep available for this platform!")
  return -1;

#endif
}
查看更多
成全新的幸福
3楼-- · 2019-01-19 14:20

I note that usleep is obsolescent but its a lot simpler than nanosleep. So I used it when I needed an enhanced sleep that would allow easy adjustment from seconds while debugging my scripts to milliseconds or zero for production.

This snooze function combines the advantages of sleep & usleep so that you can enter an int or float for your desired delay and 0.1 will sleep a 10th of a second while 3 will sleep for 3 seconds. 3.5 seconds is treated as 3 seconds.

Tested on Linux Mint 18.3 (Ubuntu 16.04.9) as C and C++ with gcc 5.4.0.

#include <unistd.h>

void snooze(double t) {(t > 1.0) ? sleep(t) : usleep(t*1000000);}

snooze(0.01);  // call function to sleep for 10ms



For completeness, this is a nanosleep version. It's potentially more accurate than the usleep version and isn't threatened by obsolescence.

#include <time.h>
#include <math.h>

void snooze(double t) {
    struct timespec req = {t, fmod(t, 1.0) * 1E9};
    nanosleep(&req, NULL);
}

// struct timespec req = {t, fmod(t, 1.0) * 1E9};
//  is equivalent to:
// struct timespec req = {0};
// req.tv_sec = t;
// req.tv_nsec = fmod(t, 1.0) * 1000000000L;

// NULL as value for *rem so no resumption after signal interrupts

snooze(1.99);  // call for delay of 1.99 seconds

As suggested by @alk, the following versions return the called sleep function's error should one occur or 0 if successful. Defining the structure rem(aining) also permits resumption after a signal interrupt.

int snooze(double t) {
    return (t > 1.0) ? sleep(t) : usleep(t*1000000);
}

int snooze(double t) {
    struct timespec req = {t, fmod(t, 1.0) * 1E9};
    struct timespec rem = {0, 0.0};
    return nanosleep(&req, &rem);
}
查看更多
Summer. ? 凉城
4楼-- · 2019-01-19 14:33

Consider select with empty FD sets and the timeout you want. From man select:

Some code calls select() with all three sets empty, nfds zero, and a non-NULL timeout as a fairly portable way to sleep with subsecond precision.

Actually it might be the best solution for any non-Windows system.

查看更多
登录 后发表回答