web-dev-qa-db-ja.com

Cのusleep()はビジーウェイトとして実装されていますか?

pthreadsを使用してマルチスレッドアプリケーションを構築していて、定期的にチェックするスレッドが必要です。このスレッドの間は、CPUを使用しないでください。これはusleep()で可能ですか? usleep()は忙しく待っていませんか?それとももっと良い解決策はありますか?

13
zeebonk

関数usleepはSUSv4から削除されました。代わりにnanosleepまたはタイマー(setitimerなど)を使用する必要があります。

R ..がコメントで述べているように、スリープをビジーウェイトとして実装する必要があります。

  • スレッドは引き続きCPUを使用します
  • 他の(優先度の低い)スレッドは実行する機会がありません

したがって:

  • シグナルを使用するものもあります(SUSv3はSIGALARMについて言及していると思いますか?)
  • 派手なタイマーを使う人もいるかもしれません
14
cnicutar

usleepはC標準の一部ではなく、古代のPOSIX標準の一部です。ただし、以下を参照してください。)

いいえ、usleepのPOSIX仕様には明確に記載されています

Usleep()関数を使用すると、呼び出し元のスレッドの実行が一時停止されます。

したがって、これには明らかに、実行を一時停止し、リソースを他のプロセスまたはスレッドに渡す必要があります。

他の人がすでに述べたように、POSIX関数nanosleepusleepに置き換わっているので、それを使用する必要があります。 C( C11 )には、nanosleepをモデルにした関数thrd_sleepがあります。

11
Jens Gustedt

Usleep()とnanosleep()の両方がシグナルによって中断される可能性があることに注意してください。 nanosleep()を使用すると、追加のtimespecポインターを渡すことができ、その場合に残り時間が保存されます。したがって、本当に遅延時間を保証する必要がある場合は、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()を確認してください。

6
Brian McFarland

Linuxでは、ビジーウェイトではない nanosleepシステムコール で実装されます。

strace を使用すると、usleep(1)の呼び出しがnanosleep({0, 1000}, NULL)に変換されることがわかります。

3
Bill Lynch

usleep()は、システムタイマーに基づいて構築されたCランタイムライブラリ関数です。
nanosleep()はシステムコールです。

MS-DOSのみ、およびilkと同様に、ビジー待機としてスリープ機能を実装します。マルチタスクを提供する実際のオペレーティングシステムは、タスクとプロセスを調整するためのメカニズムの単純な拡張として、スリープ機能を簡単に提供できます。

2
wallyk

WINE [怠惰?]はselect()の呼び出しとしてusleepを実装していることに言及する価値があります。

#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 */

(GLIBCの)nanosleepは、空の関数呼び出しにすぎないように見えることにも言及する価値があります(それ以外の場合、遅延はマイクロ秒の範囲にシフトする可能性があります)。

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