8. イベント (同期オブジェクト)
イベント (Event) は同期オブジェクトの一つです。待機中の任意のスレッドのアクセスを許可します。
8.1. TEvent
TEvent
クラス 1 は System.SyncObjs
で定義されています。
最初の書式のコンストラクタでは、名前付きのイベントを作成します (名前が空でない場合はシステムイベント)。ManualReset
パラメータが True だと、手動イベントとなり、ResetEvent()
メソッドを実行しないと非シグナル状態になりません。False だと自動リセットとなり、WaitFor()
メソッドで待機しているスレッドが処理を始めると非シグナル状態になります。InitialState
プロパティはシグナルの初期状態です。True でシグナル状態、False で非シグナル状態です。
二番目の書式のコンストラクタを使うと、無名イベントを作成します。無名イベントはローカルイベントです。手動リセット、非シグナル状態で作成されます。
constructor Create(EventAttributes: PSecurityAttributes; ManualReset, InitialState: Boolean; const Name: string; UseCOMWait: Boolean = False);
constructor Create(UseCOMWait: Boolean = False);
最初期のこのクラスは Windows API をラップしたものでした。
Delphi | Windows API |
---|---|
TEvent.Create() コンストラクタ | CreateEventA() / CreateEventW() |
TEvent.WaitFor プロパティ | WaitForSingleObject() |
TEvent.SetEvent() メソッド | SetEvent() |
TEvent.ResetEvent() メソッド | ResetEvent() |
WaitFor()
メソッドで待機しているスレッドに対して、SetEvent()
でイベント (非シグナル -> シグナル) を通知する事ができます。
See also:
8.1.1. ローカルインスタンスで使う TEvent
イベントは同期オブジェクトなので、通常はグローバルインスタンスとして作成するのですが、TThread
のフィールドとして使うと面白い事が出来ます。
次のようなユニットを作ります。
unit uEVThread;
interface
uses
System.Classes, System.SyncObjs, Vcl.StdCtrls;
type
TEvThread = class(TThread)
private
FEvent: TEvent;
FComponent: TComponent;
protected
procedure TerminatedSet; override;
public
constructor Create(Component: TComponent); overload;
destructor Destroy; override;
procedure Stop;
property Event: TEvent read FEvent write FEvent;
property Component: TComponent read FComponent write FComponent;
end;
implementation
{ TEvThread }
constructor TEvThread.Create(Component: TComponent);
begin
FEvent := TEvent.Create;
FComponent := Component;
FreeOnTerminate := True;
inherited Create(True);
end;
destructor TEvThread.Destroy;
begin
FEvent.Free;
inherited;
end;
procedure TEvThread.Stop;
begin
Terminate;
FEvent.SetEvent;
end;
procedure TEvThread.TerminatedSet;
begin
inherited;
FEvent.SetEvent;
end;
end.
フォームにメモとボタンが二つあるアプリケーションを作ります。
uses
..., uEvThread;
type
TMyThread = class(TEvThread)
protected
procedure Execute; override;
end;
...
{ TMyThread }
procedure TMyThread.Execute;
begin
inherited;
if not Terminated then
begin
TThread.Sleep(5000);
Synchronize(
procedure
begin
(Component as TMemo).Lines.Add('Start');
end
);
end;
end;
二つのボタンのイベントハンドラはこうなります。
// [Start] ボタン
procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Clear;
MyThread := TMyThread.Create(Memo1);
MyThread.Start;
end;
// [Stop] ボタン
procedure TForm1.Button2Click(Sender: TObject);
begin
MyThread.Stop; // または MyThread.Terminate;
Memo1.Lines.Add('Stop');
end;
[Start] ボタンを押してすぐに [Stop] ボタンを押しても、Sleep(5000)
はキャンセルされないため、'Start' は [Start] ボタンを押して 5 秒後に表示されます。
次に Execute()
メソッド内の Sleep(5000)
を Event.WaitFor(5000)
に変更してみます。
procedure TMyThread.Execute;
begin
inherited;
if not Terminated then
begin
// TThread.Sleep(5000);
Event.WaitFor(5000); // <-
Synchronize(
procedure
begin
(Component as TMemo).Lines.Add('Start');
end
);
end;
end;
今度は [Stop] ボタンを押すとすぐに 'Start' が表示されたと思います。もちろん、'Start' を表示しないようにする事もできます。
procedure TMyThread.Execute;
begin
inherited;
if not Terminated then
begin
Event.WaitFor(5000);
if not Terminated then // <-
Synchronize(
procedure
begin
(Component as TMemo).Lines.Add('Start');
end
);
end;
end;
See also:
8.2. TSimpleEvent
TSimpleEvent
クラス 2 は System.SyncObjs
で定義されています。
現在の実装では TSimpleEvent
クラスと TEvent
クラス (の無名イベント) に違いはありません 3 。以前もコンストラクタのみが異なっていました。
constructor TSimpleEvent.Create;
begin
inherited Create(nil, True, False, '');
end;
See also:
8.3. TLightweightEvent
TLightweightEvent
クラス 4 は軽量なイベントです。System.SyncObjs
で定義されています。但し、ローカルイベントとしてしか使えません。
.NET の ManualResetEventSlim
クラスに相当します。
See also:
#参考
索引
[ ← 7. セマフォ (同期オブジェクト) ] [ ↑ 目次へ ] [ → 9. 非同期プログラミング ライブラリ (APL) ]