Sign in Join
Wiki copytemporary

Main Loop Hooks/ja

English · Français · Slovenčina · 中文(中国) · 日本語

問題について

プログラムの中で何らかのイヴェント(あるいはソケットやパイプなど)を待たなければならなくなったとします。しかし、これをメイン (GUI) スレッドの中で行い、しかも GUI ブロックせずまたマルチスレッドにもしたくないとしたらどうしたらいいでしょうか。解決策は、新たな「ハンドル」を追加し、それをメインイヴェントループで監視することです。

解決法の詳細

ユニット LCLIntf にこれを果たすための三つの関数が追加されています。それらは:

pascal
AddEventHandler(AHandle: THandle; AFlags: dword; 
     AEventHandler: TWaitHandleEvent; AData: PtrInt): PEventHandler;
RemoveEventHandler(var AHandler: PEventHandler);
SetEventHandlerFlags(AHandler: PEventHandler; NewFlags: dword);

TWaitHandleEvent 型は、ユニット InterfaceBase の中でこう宣言されています:

pascal
TWaitHandleEvent = procedure(AData: PtrInt; AFlags: dword) of object;

AddEventHandler は、メインイヴェントループで監視できるようにハンドルを追加します。ハンドルが「シグナル」されると、AEventHandler として渡された手続きが呼び出されます。このとき、イヴェントハンドラが登録される時に渡された AData と、OS 依存の AFlags が渡されます。AddEventHandler に渡したフラグは SetEventHandlerFlags によって変更することができます。AddEventHandlerが返すハンドラ(ポインタ)は保存しておき、RemoveEventHandler によってイヴェントの監視を終了する際に同関数に渡さなければなりません。フラグが用意されている主な理由は、様々な種類のイヴェントを切り替えながら監視するための手段としてです(読む、書く、エラー)。

RemoveEventHandler は、指定のハンドルの監視を停止します。引数として AHandler をとり、これには AddEventHandler が返したポインタを渡します。RemoveEventHandler は制御を返す前に AHandler を nil に設定します。

SetEventHandlerFlags は、アクティヴなイヴェントハンドラへのフラグを変更します。現在の所、Windows では無効です(下記)が、他のプラットフォームでは利用されており、監視すべきイヴェントの種類を ON/OFF するための手段を提供しています。

Windows

現在の実装では AddEventHandler の引数 AFlags は無視され、TWaitHandleEvent の AFlags の値は 0 になります。

Win32 は次の種類のハンドルをサポートします。基本的に、MsgWaitForMultipleObjects がサポートするものです:

Gtk/Unix

AddEventHandler に渡される AFlags は、ハンドルがシグナルされるべき条件を指定します。指定可能な値は glib 中の GIOCondition 型を参照のこと。

コールバック関数(訳注: イヴェントハンドラ)側では、AFlags は上記の GIOCondition 型の中で満たされた条件を持ちます。

GTK/UNIX は次の種類のハンドルをサポートします:

Win32 はソケットとパイプをサポートしないことに注意してください(少なくとも、MSDN の中で「推奨されない」利用法です)。提案: WSAEventSelect を使ってソケット関係のイヴェントを生成し、イヴェントハンドラに渡します。

Qt4

Qt4 インターフェースは、内部的に Gtk や Win32 と異なっていますが、可能な限り GTK と同様に見えるように LCL 内でエミュレートされています。関数に渡すフラグもまた共通化されています (GIO_IN、GIO_OUT、GIO_ERR)。ユーザから見た事実上唯一の相違点は、同一のソケットにおいて、複数の種類のイヴェントが「同時に」生起しうることです。この場合、フラグを OR した一回の呼出しが行われるのではなく、複数回の呼出しが起こります。これは Qt4 の限界であり、READ や WRITE に先んじて EXCEPTION イヴェントが呼ばれてしまうのは避け難いと思われます。Qt4 インターフェースは Lazarus v0.9.29 で加えられました。

フラグ

いまのところ、引数 AFlags はウィジェットセット依存です。上記のように、Windows ではこの引数は全く用いられていませんが、Gtk や Qt などほかのプラットフォームでは、監視すべきイヴェントの種類を指定するために用いられています。

パイプとプロセス終了

クロスプラットフォームなソリューションのために、パイプ(Win32 のサポートが弱い)とプロセス(Gtk/Unix のサポートが弱い)について、追加の関数が用意されています:

pascal
TChildExitReason = (cerExit, cerSignal);
TPipeReason = (prDataAvailable, prBroken, prCanWrite);
TPipeReasons = set of TPipeReason;
 
TChildExitEvent = procedure(AData: PtrInt; AReason: TChildExitReason; AInfo: dword) of object;
TPipeEvent = procedure(AData: PtrInt; AReasons: TPipeReasons) of object;

function AddProcessEventHandler(AHandle: THandle; 
  AEventHandler: TChildExitEvent; AData: PtrInt): PProcessEventHandler;
procedure RemoveProcessEventHandler(var AHandler: PProcessEventHandler);
 
function AddPipeEventHandler(AHandle: THandle; 
  AEventHandler: TPipeEvent; AData: PtrInt): PPipeEventHandler;
procedure RemovePipeEventHandler(var AHandler: PPipeEventHandler);

プロセスが終了すると、指定のイヴェントハンドラが呼ばれます。AReason が cerExit ならば、AInfo は終了コードを持っています。AReason が cerSignal なら、AInfo は終了シグナルです(UNIX に限る)。Gtk/Unix では、AHandle として監視対象の PID を用いてください。内部的に、SIGCHLD シグナルを捕捉するためのシグナルハンドラが導入されます。Win32 では、AddEventHandler がプロセス終了を監視するのに用いられます。

パイプからの入力を監視する場合は、処理を行うためのイヴェントハンドラを AEventHandler に、ファイル識別子 (UNIX) あるいはパイプの read-end ハンドルを AHandler にして、AddPipeEventHandler に渡してください。Gtk/Unix では、AddEventHandler が呼び出され、ファイル識別子でのトラヒックを監視します。Win32 では、100 ミリ秒毎にメッセージループがタイムアウトして、監視対象のパイプを全て検査し、読み出せるデータがないか調べます。データがあれば、イヴェントハンドラが呼ばれます。

関連項目


From the Free Pascal wiki, page "Main Loop Hooks/ja", as it stood on 2020-02-19 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's Licensing page. If you have concerns about this material, message the admin.

Revision 1, last changed by WikiArchive .

Edited on wiki.freepascal.org by 3 people, 2014–2020

From the official wiki's backup of 26 May 2024: who edited this page there, and when. Edits made there after that date were not recorded, and the earlier versions are not shown here; the main page says why.

WhenWhoWhat changed
TheCreativeCATThe Japanese Page created
TheCreativeCAT問題について: Translation Added
TheCreativeCATSolution details: Translation added
TheCreativeCAT解決法の詳細: Translation completed
TheCreativeCATSee also: remnant deleted ;-) (minor)
TheCreativeCAT関連項目 o: remnant deleted (minor)
FTurtle
TrevFixed syntax highlighting; deleted category included in page template (minor)

Talk about this page

Nobody has opened a bench for this page yet. Sign in to open one.