お知らせ

電子会議

ライブラリ

パレット

Delphi FAQ検索

Delphi FAQ一覧

サンプル蔵





FDelphi FAQ
16番会議室「玉石混淆みんなで作るSample蔵」に寄せられたサンプル

"RE:1つのスレッドを何度も使いまわす"

この発言は
#00971 Satobe さんの1つのスレッドを何度も使いまわす
に対するコメントです

前回のサンプルでは、スレッド実行中に Startメソッドを呼び出 した場合に、State := 0;という初期状態から再開してくれる保証 がありませんでした。 そこで、Execute内部で Suspended:=True;が実行されるまで待つ WaitForInternalSuspendというメソッドを追加してみました。 Startメソッドに渡した SL:TStringsを途中で Freeした場合、ス レッドが動作中であるとスレッド側の処理で例外が発生してしま う可能性がありますが、このような場合にも前もって WaitForInternalSuspendメソッドを呼び出してから Freeすれば 問題ありません。 ----- ここから ----- type TMyThread = class(TThread) private FRestartFlag: Boolean; FInternalSuspendFlag: Boolean; FStartNo: Integer; FSL: TStrings; FAddStr: String; procedure Clear; procedure Add; public constructor Create; procedure Execute; override; procedure WaitForInternalSuspend(ForceSuspend: Boolean); procedure Start(SL: TStrings; StartNo: Integer); end; TForm1 = class(TForm) ..省略 private FMyThread: TMyThread; ..省略 implementation constructor TMyThread.Create; begin inherited Create(True); //Suspend状態で生成する FRestartFlag := False; FInternalSuspendFlag := False; FStartNo := 0; FSL := nil; //FreeOnTerminate := True; end; procedure TMyThread.Execute; var State, No, EndNo: Integer; begin while not Terminated do begin //例外発生で終わらないように try FRestartFlag := False; State := 0; while (not Terminated) and (not FRestartFlag) do begin case State of 0:begin Synchronize( Clear ); //FSLをクリア No := FStartNo; EndNo := No + 9; inc(State); end; 1:begin FAddStr := IntToStr(No); Synchronize( Add ); Sleep(500); //※for DEBUG inc(No); if No > EndNo then State := -1; //完了した end; else //完了したらSuspend Suspended := True; end; if FInternalSuspendFlag then begin //速やかに Suspend状態に移行 State := -1; end; end; except on E:Exception do begin if not(E is EAbort) then Application.ShowException(E); if E is EThread then Exit; Suspended := True; end; end; end; end; procedure TMyThread.WaitForInternalSuspend(ForceSuspend: Boolean); var CurrentThreadID: THandle; Msg: TMsg; begin //Execute内部で Suspended := Trueが実行されるまで待つ //ForceSuspendパラメータ // True: 実行中の処理を中断して速やかに Suspend状態にする // False: 実行中の処理が最後まで完了するのを待つ // if Suspended then Exit; //すでに Suspend状態 //念のため CurrentThreadID := GetCurrentThreadID; if CurrentThreadID = ThreadID then raise Exception.Create('同一スレッド内部から' +'WaitForInternalSuspendが呼び出されました'); FInternalSuspendFlag := ForceSuspend; try while not Suspended do begin //自分がメインスレッドならば、 //スレッドからのSynchronizeを受け付けさせる if CurrentThreadID = MainThreadID then PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE); end; finally FInternalSuspendFlag := False; end; end; procedure TMyThread.Start(SL: TStrings; StartNo: Integer); begin WaitForInternalSuspend(True); //一時停止 //リスタート情報設定 FRestartFlag := True; FStartNo := StartNo; FSL := SL; Suspended := False; //スレッド動作再開 end; procedure TMyThread.Clear; begin if Assigned(FSL) then FSL.Clear; end; procedure TMyThread.Add; begin if Assigned(FSL) then FSL.Add(FAddStr); end; //スレッドオブジェクトの生成&破棄 procedure TForm1.FormCreate(Sender: TObject); begin FMyThread := TMyThread.Create; end; procedure TForm1.FormDestroy(Sender: TObject); begin if Assigned(FMyThread) then begin FMyThread.Terminate; while FMyThread.Suspended do FMyThread.Suspended := False; FMyThread.Free; end; end; //スレッド動作開始 procedure TForm1.Button1Click(Sender: TObject); begin if Assigned(FMyThread) then begin FMyThread.Start(Memo1.Lines, StrToIntDef(Edit1.Text, 0)); end; end; ----- ここまで ----- 上記 TMyThreadクラス内部の FInternalSuspendFlag変数は、ス レッド外部から True/Flaseを書き込み、スレッド内部では参照 のみ、という扱いになっているため、クリティカルセクションな どを使った排他制御は行っておりません。 このクラスを改造して、複数スレッドから書き込みが行われるよ うな処理を行うならば、排他制御が必要になることをお忘れなく。 #「排他制御」ではなく「スレッド間の同期」というのが正しい #用語なのかしらん? 99/11/06(土) 23:35 Satobe(JCG00336) Original document by Satobe 氏 ID:(JCG00336)



ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum の16番会議室「玉石混淆みんなで作るSample蔵」に投稿されたサンプルです。これらのサンプルはボーランド株式会社がサポートする公式のものではありません。また、必ずしも動作が検証されているものではありません。これらのサンプルを使用したことに起因するいかなる損害も投稿者、およびフォーラムスタッフはその責めを負いません。使用者のリスクの範疇でご使用下さい。

Copyright 1996-2002 Delphi Users' Forum