それは「量の爆発に耐えられるの?」というものです。いまは3つのイベントを待つだけなので見通しも良いのですが、100個も200個もイベントを扱うとなるとどうでしょう。かなり豪快なプログラムになることが容易に予想できます。
そしてそれに輪を掛けるのが、「状況によってイベントを処理するハンドラは変わる」という事実です。キーボードのAが押下された、というイベントがどんな意味を持つかはまさに状況依存で、場合によっては全選択かもしれませんし、場合によっては挿入のダイアログを出せという指示かもしれません。動的にイベントハンドラの割り当てを変えようとすると、ウェイトループは仕掛けとして素朴過ぎます。
仕様書とコードの同期が取れている間は、それでもまだ我慢できるかもしれません。しかし、いったんそれらのヒモ付けが切れてしまうと、ついに地獄が始まります。例えばWinMain()とWndProc()から生で書き始めたWindowsプログラムには、多くの「微妙に絡み合った」イベント処理コードが存在しました。あれらのプログラムは一体誰が保守を行ったのでしょうか(※3)。
以上のようにウェイトループは概念としては正しいのですが、実際に使ってみると量の爆発に耐えられません。そのような理由でSymbian OSではウェイトループ(と完了待ちAPI)をラッピングし、抽象的なインターフェイスを提供するフレームワークを用意しています。それを「アクティブスケジューラ」といいます。
アクティブオブジェクト(以後、AOと略記)は前回解説したとおり、非同期要求をラッピングするクラスです。アクティブスケジューラは、これら複数のAOに対する非同期要求の完了通知(つまり広義のイベント)を一括して待つためのフレームワークです。AOを前提とするとイベントループがどのように変形できるか、概念を以下に示します。
どうでしょう、上の例だと対象イベントが増減してもコード量に変化がないことがお分かりでしょうか。しかもAOの登録・削除を行えば、動的にハンドラを切り替えるなども容易に実現可能です。もちろん完了通知に対する優先度制御も、else ifの並びとは比べものにならないくらい柔軟に行うことができます。
このようなアクティブスケジューラは以下のインターフェイスを持ちます。
ウェイトループをラッピングしたStart()とWaitForAnyRequest()を中心に、サービス自身の開始・終了やAOの登録のAPIが用意されています(アクティブスケジューラからAOを外すためのAPIは、AOの基底クラスであるCActiveにDeque()という名前で用意されています。これは発行したAO自身をアクティブスケジューラから外します)。
このアクティブスケジューラとAOを使った非同期要求のシーケンス図を以下に示します。
アクティブスケジューラはあくまでも登録されたAOの完了を検出するのが仕事ですから、最初のAOが存在しないことには処理が始められません。初期化シーケンスの期間中に、必ず最初のAOが登録されます。また初期化シーケンスは、CActiveScheduler::Start()の発行をもって完了します。この中でCActiveScheduler::WaitForAnyRequest()が発行され、以後完了通知が届くまで、当該スレッドはブロックするからです。
非同期要求の完了通知が届くと、ブロックが解除され図6のようにAOに対する処理のディスパッチが行われます。繰り返しますが、アクティブスケジューラはAOのことをCActiveだとしか思っていないのがポイントです。RunL()を介してキックされた処理がキーボードの押下処理なのか、通信回りなのかはまったく気にしていません。ほかの詳細に依存することなく、うまく機能分割ができているわけです。しかもアクティブスケジューラだとそれぞれのプロジェクトごとに、ウェイトループの問題点について「車輪の再発明」を行う必要がありません。
このように大変よく考えられた非同期フレームワークは、Symbian OSの至るところで使用されています。I/O関連、GUIのイベントなどがすべてアクティブスケジューラとアクティブオブジェクトの仕掛けの上に成り立っています。次回に解説するクライアントサーバも、この非同期フレームワークなしには成立しません。
Copyright © ITmedia, Inc. All Rights Reserved.