ビジーウェイトの概要
ビジーウェイト(busy waiting)は、ある条件が満たされるまで
プロセスが定期的に状態を確認する技術です。主に、キーボード入力の待機やリソースのロック獲得の際に利用されます。この手法は、特定の時間遅延させるためにも使用されることがあります。
素朴な実装手法とその問題点
最も基本的な実装方法としては、何も行わない「nop」命令を繰り返し実行する方法があります。この方法では、
CPUがnop命令に遭遇すると指定された時間のみ動作を停止し、ループを使って必要な遅延を実現します。しかし、
CPUの性能や処理速度の違いにより、同じ回数のループであっても経過時間が異なる場合があるため、デバイスとの入出力を扱う際には問題が生じることがあります。
特に、デバイスとの間で行うコマンドの送受信はタイミングが重要であるため、単純なビジーウェイトによる調整では不安定な動作が発生する可能性があります。異なるクロック速度の
CPUに対応するためには、プログラム開始時にnopループの速度を計測し、ビジーウェイトの回数を調整する必要があります。ただし、この方式では、実行中にクロック周波数が変動する
CPUには適応できません。
SMP(
対称型マルチプロセッシング)システムのスピンロックにおいては、特定の条件下ではビジーウェイトが機能しますが、通常は
CPUの時間を無駄にするため、効率的な手法とは考えられていません。他のスレッドを実行することができるなら、その方が遥かに効率的です。
C言語におけるビジーウェイトの例
以下に示すのは、
POSIXスレッドライブラリを使用した
C言語の例です。このプログラムでは、複数のスレッドが共有するグローバルフラグの値を使って、最初のスレッドがビジーウェイトでその変化を待機します。コンパイルには次のようにccコマンドを使用します。
```bash
$ cc -std=c11 spinlock.c -pthread
```
また、volatileキーワードはコンパイラの最適化を防ぐために使用されますが、スレッド間の同期の目的には適していません。代わりに、
ミューテックスや条件変数を利用して、安全な同期を行うべきです。後発の言語である
JavaやC#ではスレッドの標準化が進んでおり、軽量な同期手法が言語仕様に組み込まれています。
上記のプログラムでは、2番目のスレッドが60秒スリープしている間、最初のスレッドはフラグ値を監視します。
UNIX系のOSでは、`top`や`uptime`コマンドを用いて
CPUの利用状況を確認できます。プログラム実行前のロードアベレージが0.00であるのに対し、プログラム実行後には0.75に達しており、これは
CPU資源が無駄に使用された証拠です。
ビジーウェイトの代替手法
ビジーウェイトの代わりに、シグナルを利用する手法もあります。
オペレーティングシステムやスレッドライブラリには、フラグ値が変更された際に他のスレッドに通知する仕組みが備わっており、これを用いることで
CPU時間を節約できます。
イベント駆動型プログラミングとも称され、この方法はより効率的です。
また、ビジーウェイトを改善するために遅延関数を使用することが考えられます。この遅延関数は指定した時間だけスリープ状態にし、
CPUを無駄に使わずに済みます。しかし、簡単なチェックのみを行う場合でも完全に
CPUの使用を防ぐことは難しく、一部の消費は避けられません。
ビジーウェイトが適している状況
低レベルのハードウェアドライバプログラミングにおいては、ビジーウェイトが望ましい場合も存在します。すべてのデバイスに割り込み通知を実装することは困難なため、特定のデバイスの状態を確認するために、この技術が選択されることがあります。特に、デバイスからの出力待ち時間が長い場合、ビジーウェイト方式で状態変化を確認するのが一般的です。こうした状況で遅延関数を使用すると、オーバーヘッドが大きくなりがちで、結果的に
CPUリソースが無駄になってしまうことがあるため、ビジーウェイトが選択されることが多いです。