delphi.gif (306 バイト) イベントの使い方


Win32のイベントAPIを使うと、異なるスレッドやプロセスにシグナルを送ってイベントを知らせることができます。Delphiでは、このイベントがTEventとしてカプセル化されて簡単に利用できます。

 

toach.gif (917 バイト) イベントの作成

コンストラクタをつぎのように呼び出して作成します。最初の引数はセキュリティ属性なので、Windows95ではnilでかまいません。2番目と3番目の引数は、作成するアプリケーションの仕様によります。

event1 := TEvent.Create(nil, True, False, 'StartEvent');

 

toach.gif (917 バイト) シグナルの送り方

シグナルはSetEventメソッドで送ります。受け側はWaitForメソッドで待ち受けます。コンストラクタでマニュアルリセットを指定したときは、ResetEventを実行する必要があります。

 

delphi1.gif (322 バイト)

この例はスレッドにシグナルを送り、スレッドがカウンタをインクリメントするのを制御する例です。

 

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, Unit2, StdCtrls, SyncObjs, ExtCtrls;

type
TForm1 = class(TForm)
cmdSet: TButton;
cmdReset: TButton;
txtCount: TEdit;
Timer1: TTimer;
cmdCountClear: TButton;
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure Timer1Timer(Sender: TObject);
procedure cmdSetClick(Sender: TObject);
    procedure cmdResetClick(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure cmdCountClearClick(Sender: TObject);
private
    { Private 宣言 }
    event1, event2: TEvent;
thread: TMyThread;
public
    { Public 宣言 }
end;

var
Form1: TForm1;
count: Longint;

implementation

{$R *.DFM}

{ フォームが作成されたとき }
procedure TForm1.FormCreate(Sender: TObject);
begin
    count := 0;
    event1 := TEvent.Create(nil, True, False, 'StartEvent'); // イベントオブジェクト作成
    event2 := TEvent.Create(nil, True, False, 'StopEvent'); // イベントオブジェクト作成
    thread := TMyThread.Create(False);    // スレッド作成
end;

{ フォームを閉じるとき }
procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
    thread.Destroy;
end;

{ スレッドがカウンタを更新することを確認するため }
procedure TForm1.Timer1Timer(Sender: TObject);
begin
txtCount.Text := IntToStr(count);
end;

{ スレッドがカウントするのを許可 }
procedure TForm1.cmdSetClick(Sender: TObject);
begin
    event1.SetEvent;
end;

{ スレッドがカウントするのを禁止 }
procedure TForm1.cmdResetClick(Sender: TObject);
begin
    event2.SetEvent;
end;

{ 閉じようとしたとき }
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
    thread.Terminate; // スレッドを終了させる
end;

{ カウンタクリア }
procedure TForm1.cmdCountClearClick(Sender: TObject);
begin
    count := 0;
end;

end.

 

{ スレッド側 }

unit Unit2;

interface

uses
Classes, Forms, Windows, SyncObjs;

type
TMyThread = class(TThread)
private
    { Private 宣言 }
    event1, event2: TEvent;
    enabled: Boolean; // カウントイネーブル
protected
    procedure Execute; override;
public
    constructor Create(CreateSuspended: Boolean);
end;

implementation

{注意: VCL のメソッド/関数/プロパティを扱うには、以下のように
Synchronize メソッドの引数として渡したメソッドの中から扱う必要があります。

    Synchronize(UpdateCaption);

UpdateCaption の中では以下のように VCL を呼び出すことができます。

    procedure TMyThread.UpdateCaption;
    begin
    Form1.Caption := 'スレッドから書き換えました';
    end; }

{ TMyThread }

uses Unit1;

{ スレッドが作成されたとき }
constructor TMyThread.Create(CreateSuspended: Boolean);
begin
    inherited Create(CreateSuspended);
    event1 := TEvent.Create(nil, True, False, 'StartEvent');
    event2 := TEvent.Create(nil, True, False, 'StopEvent');
    enabled := False;
end;

{ Unit1のcountをインクリメントするワーキングスレッド }
procedure TMyThread.Execute;
var
    r: TWaitResult;
begin
{ スレッドとして実行したいコードをここに記述 }
while True do
begin
    if Terminated then
        Exit;
    r := event1.WaitFor(10); // 開始信号があるか
    if r = wrSignaled then
    begin
        enabled := True;
event1.ResetEvent;
    end;
    r := event2.WaitFor(10); // 停止信号があるか
    if r = wrSignaled then
begin
        enabled := False;
event2.ResetEvent;
end;
    if enabled then // enabledフラグがTrueならカウント
        Inc(count);
    Application.ProcessMessages;
end;
end;

end.