pthreads
を使用してマルチスレッドアプリケーションを構築していて、定期的にチェックするスレッドが必要です。このスレッドの間は、CPUを使用しないでください。これはusleep()
で可能ですか? usleep()
は忙しく待っていませんか?それとももっと良い解決策はありますか?
関数usleep
はSUSv4から削除されました。代わりにnanosleep
またはタイマー(setitimer
など)を使用する必要があります。
R ..がコメントで述べているように、スリープをビジーウェイトとして実装する必要があります。
したがって:
(usleep
はC標準の一部ではなく、古代のPOSIX標準の一部です。ただし、以下を参照してください。)
いいえ、usleep
のPOSIX仕様には明確に記載されています
Usleep()関数を使用すると、呼び出し元のスレッドの実行が一時停止されます。
したがって、これには明らかに、実行を一時停止し、リソースを他のプロセスまたはスレッドに渡す必要があります。
他の人がすでに述べたように、POSIX関数nanosleep
がusleep
に置き換わっているので、それを使用する必要があります。 C( C11 )には、nanosleep
をモデルにした関数thrd_sleep
があります。
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()
を確認してください。
Linuxでは、ビジーウェイトではない nanosleepシステムコール で実装されます。
strace を使用すると、usleep(1)
の呼び出しがnanosleep({0, 1000}, NULL)
に変換されることがわかります。
usleep()
は、システムタイマーに基づいて構築されたCランタイムライブラリ関数です。nanosleep()
はシステムコールです。
MS-DOSのみ、およびilkと同様に、ビジー待機としてスリープ機能を実装します。マルチタスクを提供する実際のオペレーティングシステムは、タスクとプロセスを調整するためのメカニズムの単純な拡張として、スリープ機能を簡単に提供できます。
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;
}