Difference between revisions of "Main Loop Hooks/ja"

From Free Pascal wiki
Jump to navigationJump to search
(→‎Solution details: Translation added)
(→‎解決法の詳細: Translation completed)
Line 30: Line 30:
 
=== Windows ===
 
=== Windows ===
  
The AFlags parameter in AddEventHandler is unused, and the AFlags in TWaitHandleEvent will be 0, in the current implementation.
+
現在の実装では AddEventHandler の引数 AFlags は無視され、TWaitHandleEvent の AFlags の値は 0 になります。
  
Win32 supports the following handle types, basically the things supported by MsgWaitForMultipleObjects:
+
Win32 は次の種類のハンドルをサポートします。基本的に、MsgWaitForMultipleObjects がサポートするものです:
* change notifications (for files and directories)
+
* 変更通知 (ファイルとディレクトリの)
* console input
+
* コンソール入力
* events: signalled with SetEvent winapi function
+
* イヴェント: SetEvent WinAPI 関数でシグナルされる
* mutexes: signalled when it is not owned anymore
+
* ミューテックス: 所有されなくなるとシグナルされる
* processes: signalled when they terminate
+
* プロセス: 終了するとシグナルされる
* semaphore: signalled when it's ''count'' is greater than zero
+
* セマフォ: ''カウント''が 0 を超えるとシグナルされる
* threads: signalled when they terminate
+
* スレッド: 終了するとシグナルされる
* timers: signalled when expired, see SetWaitableTimer
+
* タイマ: 指定時間経過後シグナルされる
  
 
=== Gtk/Unix ===  
 
=== Gtk/Unix ===  
  
The AFlags parameter in AddEventHandler specifies the condition in which the handle should be signalled, with the possible values being the ones documented in the GIOCondition type in the [http://developer.gimp.org/api/2.0/glib/glib-IO-Channels.html#GIOCondition glib] reference.
+
AddEventHandler に渡される AFlags は、ハンドルがシグナルされるべき条件を指定します。指定可能な値は [http://developer.gimp.org/api/2.0/glib/glib-IO-Channels.html#GIOCondition glib] 中の GIOCondition 型を参照のこと。
  
In the callback, the AFlags will contain the condition, of the above referenced GIOCondition type, that was satisfied.
+
コールバック関数(訳注: イヴェントハンドラ)側では、AFlags は上記の GIOCondition 型の中で満たされた条件を持ちます。
  
Gtk/unix supports the following handle types:
+
GTK/UNIX は次の種類のハンドルをサポートします:
* files
+
* ファイル
* sockets
+
* ソケット
* pipes
+
* パイプ
  
Note that win32 does not support sockets or pipes (at least, their use is "discouraged" by MSDN). Suggestion: use WSAEventSelect to create an event associated with a socket and pass the event handle.
+
Win32 はソケットとパイプをサポートしないことに注意してください(少なくとも、MSDN の中で「推奨されない」利用法です)。提案: WSAEventSelect を使ってソケット関係のイヴェントを生成し、イヴェントハンドラに渡します。
  
 
=== Qt4 ===
 
=== Qt4 ===
  
The Qt4 interface is internally different from Gtk and Win32, but has been emulated within LCL as close as possible to the GTK logic. Even the flags passed have been made compatible (GIO_IN, GIO_OUT and GIO_ERR). The only actual difference for the user is that should 2+ event types happen on the same socket "at once" the callback will not be called with an OR-ed version of the flags, but instead called twice in a row. This is a Qt4 limitation and the possibility of calling EXCEPTION event before a READ or WRITE event is to my knowledge unavoidable. The Qt4 interface was added in Lazarus v0.9.29 trunk (so it should appear in 0.9.30 stable).
+
Qt4 インターフェースは、内部的に Gtk Win32 と異なっていますが、可能な限り GTK と同様に見えるように LCL 内でエミュレートされています。関数に渡すフラグもまた共通化されています (GIO_IN、GIO_OUT、GIO_ERR)。ユーザから見た事実上唯一の相違点は、同一のソケットにおいて、複数の種類のイヴェントが「同時に」生起しうることです。この場合、フラグを OR した一回の呼出しが行われるのではなく、複数回の呼出しが起こります。これは Qt4 の限界であり、READ や WRITE に先んじて EXCEPTION イヴェントが呼ばれてしまうのは避け難いと思われます。Qt4 インターフェースは Lazarus v0.9.29 で加えられました。
  
=== Flags ===
+
=== フラグ ===
  
Currently the FLAGS parameters are widgetset specific. On windows, this parameter is completely unused (see above), but on Gtk, Qt and others it is used to set what type of events to watch.
+
いまのところ、引数 AFlags はウィジェットセット依存です。上記のように、Windows ではこの引数は全く用いられていませんが、Gtk や Qt などほかのプラットフォームでは、監視すべきイヴェントの種類を指定するために用いられています。
  
=== Pipes and Process Termination ===
+
=== パイプとプロセス終了 ===
  
To provide a cross-platform solution for pipes (not well supported on win32) and processes (not well supported on gtk/unix) additional functions have been added:
+
クロスプラットフォームなソリューションのために、パイプ(Win32 のサポートが弱い)とプロセス(Gtk/Unix のサポートが弱い)について、追加の関数が用意されています:
  
<syntaxhighlight>TChildExitReason = (cerExit, cerSignal);
+
<syntaxhighlight>
 +
TChildExitReason = (cerExit, cerSignal);
 
TPipeReason = (prDataAvailable, prBroken, prCanWrite);
 
TPipeReason = (prDataAvailable, prBroken, prCanWrite);
 
TPipeReasons = set of TPipeReason;
 
TPipeReasons = set of TPipeReason;
Line 80: Line 81:
 
function AddPipeEventHandler(AHandle: THandle;  
 
function AddPipeEventHandler(AHandle: THandle;  
 
   AEventHandler: TPipeEvent; AData: PtrInt): PPipeEventHandler;
 
   AEventHandler: TPipeEvent; AData: PtrInt): PPipeEventHandler;
procedure RemovePipeEventHandler(var AHandler: PPipeEventHandler);</syntaxhighlight>
+
procedure RemovePipeEventHandler(var AHandler: PPipeEventHandler);
 +
</syntaxhighlight>
  
When a process terminates the event handler specified will be called. AInfo will contain the exit code if AReason is cerExit, or (on unix only) the termination signal if AReason is cerSignal. For gtk/unix, use the PID to watch as AHandle. Internally, a signal handler is installed to catch the SIGCHLD signal. On win32, AddEventHandler is used to watch process termination.
+
プロセスが終了すると、指定のイヴェントハンドラが呼ばれます。AReason が cerExit ならば、AInfo は終了コードを持っています。AReason が cerSignal なら、AInfo は終了シグナルです(UNIX に限る)。Gtk/Unix では、AHandle として監視対象の PID を用いてください。内部的に、SIGCHLD シグナルを捕捉するためのシグナルハンドラが導入されます。Win32 では、AddEventHandler がプロセス終了を監視するのに用いられます。
  
To watch a pipe for incoming data, pass the file descriptor (unix) or the pipe read-end handle to AddPipeEventHandler with a custom chosen event handler method as AEventHandler. On gtk/unix, AddEventHandler is called to watch the file descriptor for traffic. On win32, the message loop will timeout every 100 msecs to check all watched pipes for available data; if data is available, the event handler is called.
+
パイプからの入力を監視する場合は、処理を行うためのイヴェントハンドラを AEventHandler に、ファイル識別子 (UNIX) あるいはパイプの read-end ハンドルを AHandler にして、AddPipeEventHandler に渡してください。Gtk/Unix では、AddEventHandler が呼び出され、ファイル識別子でのトラヒックを監視します。Win32 では、100 ミリ秒毎にメッセージループがタイムアウトして、監視対象のパイプを全て検査し、読み出せるデータがないか調べます。データがあれば、イヴェントハンドラが呼ばれます。
 +
 
 +
== 関連項目 o==
 +
 
 +
* [[Asynchronous Calls]]
 +
* [[Multithreaded Application Tutorial]]
 +
 
 +
[[Category:LCL]]
  
 
==See also==
 
==See also==

Revision as of 17:21, 19 March 2014

English (en) français (fr) 日本語 (ja) slovenčina (sk) 中文(中国大陆)‎ (zh_CN)

問題について

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

解決法の詳細

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

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

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

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 がサポートするものです:

  • 変更通知 (ファイルとディレクトリの)
  • コンソール入力
  • イヴェント: SetEvent WinAPI 関数でシグナルされる
  • ミューテックス: 所有されなくなるとシグナルされる
  • プロセス: 終了するとシグナルされる
  • セマフォ: カウントが 0 を超えるとシグナルされる
  • スレッド: 終了するとシグナルされる
  • タイマ: 指定時間経過後シグナルされる

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 のサポートが弱い)について、追加の関数が用意されています:

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 ミリ秒毎にメッセージループがタイムアウトして、監視対象のパイプを全て検査し、読み出せるデータがないか調べます。データがあれば、イヴェントハンドラが呼ばれます。

関連項目 o

See also