|
|
≪イベント≫ |
| ソフトウェアの動作とは結局、「イベントのハンドリング」なので(言い切って良いのか?)、事象においてのイベントの定義がキッチリされていれば、ハンドリングするのは容易な事。
図イ-1
図イ-1は、あらゆるソフトが持つメインループの構造。 WindwosなどのイベントドリブンなOSのプログラミングは、図イ-1の右側の「イベント処理」だけをコーディングする事を要求される。(実際はWinMain()があるけど隠されている) じゃあ、実際何を待つの?って事がイベントの定義がキッチリされているかどうかという事になる。
よくあるのが(本当か?)、グローバル変数によるフラグ監視のやり方。 メインループは、このフラグの監視とフラグ変化の応答処理で構成される。筆者も15年以上前はこのやり方だった。非常に小さいシステムは、これで十分機能するし目も行き届く。 しかし、フラグによるイベントの伝達はレベルトルガであるためフラグを立てた側が要求を取り下げる必要がある。また多重イベントを処理できない。等の不都合がある。 FPGAとかのプログラミングの場合には、1を書くリクエストが実は書き込みをしないという様な事が可能である。しかしマイコンのメモリシステムでは1を書くと1が書かれてしまうのでうまくない。また、FPGAにおいても多重イベントを許可するためにはFIFOを採用することになる。
図イ-2
イベントはFIFOの様なキューと親和性がある。というのも、イベントはほとんどの場合において、発生した事が意味を持つからで、発生している事には意味が無いからである。 イベントの取りこぼしさえ起こさなければ、ちょうどオルタネートプッシュスイッチのようなもので、内部ステートで管理すれば、イベントが発生している事を認識する事ができる。
図イ-3
図イ-3は、キーの押下と開放が2回発生し、新たにキーの押下が発生しているイベントFIFOである。 イベントの取り出しが間に合わない時、多重イベントとなる。FIFOによるバッファリングは多重イベントをうまく処理できる。たとえば、ダブルクリックの様なものは特別な処理も無く対応できる。 ただし、多重イベントの蓄積によるバッファオーバーフローには注意する必要がある。 テクニック的にはバッファ以上のイベントは無視するしかなく、クリティカルな条件では破綻するのは理解できると思う。これに対する特効薬は無く、破綻させないようにすべきである。(図イ-4)
図イ-4
FIFOによるイベントの実装は、多重イベントの処理に向いているが、多重にしたくないものも多重で受けてしまうという欠点もある。 その場合、イベントの発生を抑えるか、イベントFIFOから取り出す時に無視するかのいずれかで対応する。 前者の場合イベント発生源がイベントをどう処理しているかの情報を持つ必要があるので好ましくなく、後者の場合、FIFOには溜まってしまうので、破綻させないFIFOの長さが必要になる。
FIFOを使う際の問題点として、FIFOは常に一方通行であるという事実もある。 つまり書く側から読む事はできず、読む側から書く事ができない。もちろん決してできない訳ではない。 しない方が安全という事である。なぜ、しない方が安全かは後述する「キュー」で説明する。 では、書く側と読む側とは何か。書く側はイベント発生源であり、読む側がイベント処理側である。 組込の場合、イベントには「割り込みイベント」と「非割り込みイベント」がある。 |
|
≪割り込みイベント≫ |
| 「ボタン及びキー処理」の様なイベントは、割り込みイベントであるのが理想である。割り込みイベントと言っても割り込み入力を使う訳ではなく、割り込み(キーの場合はタイマ割り込み)の中でイベントキューに追加される。
図割イ-1
イベントキューへの書き込みは、全割り込みで共有されるため、割り込みは多重割り込みを禁止しなければならない。(割り込み中は割り込みがかからない) 割り込み中のイベントは全てイベントキューに追加されるので、適切にキューから引き上げる事ができれば、イベントのハンドリングは簡単になる。 通常はフォアグラウンドでイベントキューから取り出し、適切なアクションを行う事になる。
注意しなければならない事が1つ。割り込みイベントに対するアクションの中でタイムクリティカルなものは、割り込みの中で処理しなければならない事。 この場合、「処理しましたイベント」をイベントキューに追加して、フォアグラウンドで認識する事になる。 |
|
≪非割り込みイベント≫ |
| イベントを処理する事に連動して、新たなイベントが発生する事がある。たとえば、キーのイベントに連動して、内部シーケンスを進めて行く様な場合、シーケンス変更イベントが発生する。 この場合は、非割り込みにおいてイベントが発生するため、先のイベントキューと同一のキューに追加する事ができない。 このため、イベントキューを2つ持ち、「割り込みイベント」を「イベント」、「非割り込みイベント」を「メッセージ」として区別する。
図非イ-1
メッセージを処理する側はフォアグラウンド、追加する側もフォアグラウンドなので、読み書きの区別が保たれる。 イベントキューは書き込み側が割り込み、読み出し側がフォアグラウンドとなる。 |
|
≪イベントハンドリング≫ |
| 割込み、非割込みなどの様々なイベントを処理する部分がないとソフトとしては機能しない。 オーソドックスなのはシーケンス制御の様なループ構造のメインループ。
図メ−1
正しくはオーソドックスかどうか不明。筆者はよっぽど非力なCPUでないと、この方法は使わない。 OSを使わない場合、ほとんどの皆さんはコレではないだろうか。
実は制御ソフトというのはその処理のほとんどにおいて、イベントハンドリングばっかりしている。 イベントは前の状態と今の状態の差で発動させる。 具体的には、前の状態を保持する変数があって、今の状態と違っていれば、サブルーチンを呼ぶとかする事になる。 変数への保存や比較する部分をメインループやサブルーチン部分に記述する事になる。 これでも小規模なモノは十分うまく動く。 ただ、この部分は本来したい動作ではない。 本来したかった事は『何か外部の制御』であって、『イベントハンドリングなどの制御構造』ではない。 ソフトの規模を大きくするためには、制御構造を単純化させる必要がある。 具体的には制御構造が必然的に機能を表す様な構造を採用する必要がある。
OSレスでイベントハンドリングを行うには、メッセージモデルが最適だと、筆者は思う。 |
|
≪メッセージ≫ |
| 筆者がメッセージモデルと出会ったのは、Windows3.0からである。 組込の話をしているのに、Windowsは関係無いと思われるかもしれないが、「イベントドリブン」という考え方は、それ以前の組込モデルには見られなかった。(筆者が知らかっただけだとも思われるが) 前述した様に、非割り込みのイベントを処理するのがメッセージという事になる。 メッセージというのは今の生活に例えると、メールに似ている。そして割り込みは電話に似ている。 メールは送ってさえ置けば、相手がいつ見るかは大した問題ではない。反対に電話はかけた時に相手が出る事が前提となる。
|
|
≪キュー
≫ |
| |
|
≪テキスト表示≫ |
| |
|
≪静的記憶
≫ |
| |