Islele() в C реализовано как ожидание?

Я создаю многопоточное приложение с pthreads и нуждаюсь в потоке, чтобы периодически проверять некоторые вещи. За время между этим потоком не следует использовать какой-либо процессор. Возможно ли это с помощью usleep()? Ожидается ли usleep() ожидание? Или есть лучшее решение?

Ответ 1

Функция usleep была удалена из SUSv4. Вероятно, вы должны использовать вместо nanosleep или таймеры (setitimer и т.д.).

Как замечает R.. в комментариях, если сон будет реализован как оживленное ожидание:

  • В потоке будет продолжаться использование CPU
  • В других (более низкоприоритетных) потоках не будет возможности запускать

Таким образом:

  • Некоторые могут использовать сигналы (я думаю, SUSv3 упомянул SIGALARM?)
  • Некоторые могут использовать модные таймеры

Ответ 2

(usleep не является частью стандарта C, но является древним стандартом POSIX, но см. ниже)

Нет, в спецификации POSIX usleep четко сказано

Функция usleep() приведет к приостановке выполнения вызывающего потока...

так что это явно требует, чтобы он приостанавливал выполнение и передавал ресурсы другим процессам или потокам.

Как уже упоминалось другими, функция POSIX nanosleep теперь заменяет usleep и вы должны это использовать. C (начиная с C11) имеет функцию thrd_sleep которая смоделирована после nanosleep.

Ответ 3

Просто помните, что и usleep(), и nanosleep() могут быть прерваны сигналом. nanosleep() позволяет вам передать дополнительный указатель времени, в котором оставшееся время будет сохранено, если это произойдет. Поэтому, если вам действительно нужно гарантировать время задержки, вы, вероятно, захотите написать простую оболочку вокруг nanosleep().

Остерегайтесь, что это не проверено, но что-то вроде этого:

int myNanoSleep(time_t sec, long nanosec)
{
   /* Setup timespec */
   struct timespec req;
   req.tv_sec = sec;
   req.tv_nsec = nanosec;

   /* Loop until we've slept long enough */
   do 
   {
      /* Store remainder back on top of the original required time */
      if( 0 != nanosleep( &req, &req ) )
      {
          /* If any error other than a signal interrupt occurs, return an error */
          if(errno != EINTR)
             return -1; 
      }
      else
      {
          /* nanosleep succeeded, so exit the loop */
          break;
      }
   } while( req.tv_sec > 0 || req.tv_nsec > 0 )
   return 0; /* Return success */
}

И если вам когда-либо понадобится разбудить поток для чего-то другого, кроме периодического таймаута, посмотрите на переменные состояния и pthread_cond_timedwait().

Ответ 4

В Linux он реализован с помощью наноселективного системного вызова, который не является ожиданным ожиданием.

Используя strace, я вижу, что вызов usleep(1) переводится в nanosleep({0, 1000}, NULL).

Ответ 5

usleep() - это функция библиотеки времени выполнения, построенная на системных таймерах.
nanosleep() - системный вызов.

Только MS-DOS и, подобно ilk, реализуют функции ожидания как занятые ожидания. Любая реальная операционная система, которая предлагает многозадачность, может легко обеспечить функцию сна как простое расширение механизмов координации задач и процессов.

Ответ 6

Стоит отметить, что WINE [lazily?] Реализует usleep как вызов select():

#ifndef HAVE_USLEEP
int usleep (unsigned int useconds)
{
#if defined(__EMX__)
    DosSleep(useconds);
    return 0;
#elif defined(__BEOS__)
    return snooze(useconds);
#elif defined(HAVE_SELECT)
    struct timeval delay;

    delay.tv_sec = useconds / 1000000;
    delay.tv_usec = useconds % 1000000;

    select( 0, 0, 0, 0, &delay );
    return 0;
#else /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
    errno = ENOSYS;
    return -1;
#endif /* defined(__EMX__) || defined(__BEOS__) || defined(HAVE_SELECT) */
}
#endif /* HAVE_USLEEP */

Стоит также упомянуть, что nanosleep (в GLIBC), кажется, немного больше, чем пустой вызов функции (что-нибудь еще, и задержка может сместиться в микросекундный диапазон).

/* Pause execution for a number of nanoseconds.  */
int
__libc_nanosleep (const struct timespec *requested_time,
                  struct timespec *remaining)
{
  __set_errno (ENOSYS);
  return -1;
}