メッセージループ
[Wikipedia|▼Menu]

イベントループ (event loop)、メッセージディスパッチャ (message dispatcher)、メッセージループ (message loop)、メッセージポンプ (message pump)、ランループ (run loop) とは、プログラム内でイベントメッセージを待ち受け、それらをディスパッチ(配送)する構成要素である。内部または外部の「イベントプロバイダー」(通常、イベントが到着するまで要求をブロックする)に要求することで動作し、次いで適当なイベントハンドラー (event handler) を呼び出す(イベントのディスパッチ)。イベントプロバイダーが後述のファイルインタフェースに従う場合、イベントループは reactor と連携する形で使われることがあり、select() または poll() を使ってファイルインタフェースにアクセスする。イベントループはほぼ常にメッセージの発信元とは非同期に動作する。

イベントループはプログラムの中心的制御構造となっていることが多い。そのためそれをメインループ (main loop) またはメインイベントループ (main event loop) とも呼ぶ。そのようなプログラムではイベントループが最上位の制御構造となっており、そのため「メイン」と名づけられている。
メッセージパッシング

メッセージポンプという呼称は、プログラムのメッセージキュー(通常OSが割り当て、OSが所有する)からメッセージを汲み上げ、そのプログラム内で処理することに由来する。厳密には、イベントループはプロセス間通信の実装法の1つである。実のところメッセージ処理は多くのシステムに存在し、例えばMachカーネルレベルのコンポーネントにもある。イベントループはメッセージを使用するシステムの実装技法の1つである。
代替手法

この手法は以下のような他の手法とは対照的である:

古くからある、単純に一回動作して終了するプログラム。この種のプログラムは情報処理の最初期からあり、ユーザーとの対話手段を持たない。現在も主に
CUI指向のプログラムでよく使われている。各種パラメータを指定して起動される。

メニュー駆動型設計。この場合も一種のメインループは存在するが、ユーザーから見てイベント駆動的ではない。イベント駆動の代わりとして、階層型のメニューを順次選択していって、希望する動作を指定する。このメニューを通した限定的な対話性がある。

GUIが主流となったため、多くのアプリケーションがメインループを持つようになった。get_next_message() というルーチンは一般にOSが提供するもので、メッセージが到着するまでブロックされる。したがってこのループが動作するのは処理すべきものが存在する場合だけである。function main initialize() while message != quit message := get_next_message() process_message(message) end whileend function
ファイルインタフェース

UNIXでは「あらゆるものはファイルである」というパラダイムにより、ファイルベースのイベントループが自然に生まれた。ファイルの読み書きだけでなく、プロセス間通信、ネットワーク通信、デバイス制御が全てファイルI/Oで行われ、対象はファイル記述子で指定される。selectおよびpollシステムコールを使えば、複数のファイル記述子の状態変化を同時に監視でき、読み込むべきデータが到着したことを検知できる。

例として、継続的に更新されるファイルから読み込んでその内容を X Window System に表示するPythonプログラムを示す。クライアントとはソケットを通じて通信する。main(): file_fd = open ("logfile") x_fd = open_display () construct_interface () while changed_fds = select ({file_fd, x_fd}): if file_fd in changed_fds: data = read_from (file_fd) append_to_display (data) send_repaint_message () if x_fd in changed_fds: process_x_messages ()
シグナル処理

UNIXでファイルインタフェースに従わない数少ない例として、非同期イベント(シグナル)がある。シグナルはシグナルハンドラで受信する。シグナルハンドラは小さな制限されたコードであり、それが動作中はプログラム本体の処理はサスペンドされる。select()でブロック中にシグナルを受信して処理した場合、selectはEINTRというエラーコードを伴って早期に戻る。プログラムがCPUを使用している間にシグナルを受信すると、シグナルハンドラを実行する間は本体の実行がサスペンドされる。

したがってシグナルを考慮するには、シグナルハンドラで大域変数のフラグをセットし、イベントループのselect()呼び出しの直前と直後でそのフラグをチェックすればよい。フラグがセットされていたら、ファイル記述子でのイベントと同様にシグナルを処理する。しかしながら、この技法では競合状態が生じる。フラグのチェックとselect()呼び出しの間にシグナルが到着した場合、select()が他の理由で戻るまでシグナルを処理できない。

この問題を解決するため、POSIXではpselectシステムコールを提供している。これはselectに似ているがsigmaskという引数が追加されており、シグナルのマスクを設定できる。これを使えば、普段はシグナルをマスクしておき、selectを呼び出している間だけマスクを解除することができる。すると、シグナルは select がイベントを待ち受けている間だけ受信されることになる。ただし、pselect()が利用可能となったのは比較的最近のことで、たとえばLinuxの場合、Linuxカーネルのバージョン2.6.16より以前の版ではpselect()システムコールは実装されておらず、glibcでは競合状態の問題をはらんだ実装がなされていた。

より汎用的な代替技法として、非同期イベントをself-pipe trickと呼ばれる技法でファイルベースのイベントに変換してやる技法がある[1]。これはシグナルハンドラでパイプに1バイトを書き込み、そのパイプのもう一方の端を主プログラムがselectで監視するという技法である[2]。Linuxカーネル 2.6.22では、signalfd()という新システムコールが追加された。これはシグナル受信用の特別なファイル記述子を生成する。
実装例
Windowsアプリケーション

Windowsにてユーザーとやりとりするプロセスを動作させる場合、イベントに応答するためのメッセージループが必須である。Windowsではイベントとメッセージは同等視される[注釈 1]。イベントとしては、ユーザーとのやりとり、ネットワークのトラフィック、システム処理、タイマー、プロセス間通信などがある。


次ページ
記事の検索
おまかせリスト
▼オプションを表示
ブックマーク登録
mixiチェック!
Twitterに投稿
オプション/リンク一覧
話題のニュース
列車運行情報
暇つぶしWikipedia

Size:25 KB
出典: フリー百科事典『ウィキペディア(Wikipedia)
担当:undef