システムの応答性

例えば、こんなプログラムがあったとする。

int main()
{
    while(1) {
        if (SW1==TRUE) {        // スイッチ1ON?
            LED_BLINK=TRUE;   // LED点滅開始
        }
        if (SW2==TRUE) {         // スイッチ2ON?
              LED_BLINK=FALSE;
        }
        if (LED_BLINK==TRUE) {
            LED = 1;                // LED点灯
           wait(1);                  // 1秒間待ち
            LED = 0;                // LED消灯
           wait(1);                  // 1秒間待ち
        }
    }
    return 0;
}

 スイッチ1(SW1)を押したらLEDが1秒間隔で点滅し、スイッチ2(SW2)を押したら、点滅を止めるという単純なプログラムである。
一見すると、何の問題も無いように見える。(少なくともロジックは間違っていない)    ...が、しかしこのプログラムは操作性が極めて悪い。

 プログラムの動作を、時間軸に沿ってみてみると、下の様になる。



 一見して分かるように、スイッチの状態を読み取る動作は、処理時間のほんの僅かしかない。従って、

  • スイッチの状態を読み取る処理が動いているときにスイッチ操作するか
  • スイッチを押し続けるか

 の操作をしない限り、プログラムは反応しないことになる。

 問題は、LEDの点灯時間を決めているwait()で、この処理が動いている間は、他の処理を受け付けないという所にある。
 従って、応答性の良いシステムを作ろうとしたら、長時間のwait()や、処理を作ってはいけない。

 この例では、以下の様にプログラミングすると、問題を解決できる。(ただし、点灯時間はアバウト)

int main()
{
    int  time;  // 変数の値の範囲に注意
    while(1) {
    time++;
        if (SW1==TRUE) {        // スイッチ1ON?
            LED_BLINK=TRUE;   // LED点滅開始
        }
        if (SW2==TRUE) {         // スイッチ2ON?
              LED_BLINK=FALSE;
        }
        if (LED_BLINK==TRUE) {
            if (time > 99999) {      // 99999は一秒に相当する数。ループを回る回数で時間を計る。
                LED ~= LED;           // LED点灯/消灯切り替え
                time = 0;
            }
        }
    }
    return 0;
}

 このプログラムでは、下図の様に、スイッチの読み取り動作が短い時間間隔で行われるので、スイッチを押す動作(=イベント)の取りこぼしが無い。


プログラムを設計する際は、

  • イベントの間隔
  • イベントの継続時間

に対して、イベントを読み取る周期が十分短い様に設計しなければならない。

         
 ループを使ってスイッチなどの状態を繰り返し確認する手法は「ポーリング」と呼ばれている。ポーリングに対する手法として、割り込みがある。

 ポーリングの手法としての長所・短所は以下の通り。

  • 簡易に実装でき、コスト(=処理時間、コーディング量)も比較的小さくて済む
  • 限界まで応答時間を短くできる(限定された条件で)
  • 純粋にシーケンシャルな動作なので、並列動作に係る意味不明なバグに悩まされることは少ない。
  • 応答時間を厳密に制御できない
  • システムの状態や負荷によっては、イベントを取りこぼす(あらゆるケースにおいて、応答時間を事前に見積もるのは、結構大変な作業)

 ポーリングの欠点を解消する手段として、割り込みを使って実装が行われることも多い。ただし、割り込みでポーリングをすべて代替出来る訳ではないし、割り込みの方がポーリングより優れているという訳でもない。ケースバイケースで使い分けを行うことが肝要である。

最終更新:2016年01月28日 14:16