現在、DelphiでDLLを作成しています。
そのDLLの上位アプリはBCB、Delphi等で使います。
DLL内でスレッド(TThread)を使用してその終わりを待ちたいのですが、うまく
いきませんのでご教授いただければと思います。
全てのソースではないですが、簡略したものを記します。
実際には他のスレッドも作成し、複数のスレッドを実行させたいと思っています。
いろいろ検索してOnTerminatedを自前のクラス(TMethodHolder)を作成すれば
終了検知が出来るとまでは解ったのですが、うまく行きません。
TMethodHolderと言うクラスを作成してTThreadのOnTerminatedをThreadDoneに関
連づけているのですが、TKCheckThread.Executeが終了しても呼ばれないために
repeat
Application.ProcessMessages;
Sleep( 1 );
until ( MethodHolder.Terminated );
で、永久ループに陥ってしまっています。
とりあえずTKCheckThreadに終了フラグを作成してそれをrepeart untilでループ
させると成功しますが、スマートではないので出来たらイベント処理でスレッド
の終わりを待ちたいのですが、どうすればOnTerminatedを関連づけることが出来
るのでしょうか?
WaitForも使ってみたのですが、WaitForだとメインスレッドも止まってしまうた
め今回には適さないので使えませんでした。
DelphiはXEを使っています。
以上ですがよろしくお願いします。
>=== libcheck.dllソース
library libcheck;
uses
SysUtils,
Classes,
ShlObj,
Windows,
Messages,
Dialogs,
Controls,
Shellapi,
Forms,
KCheckThread in 'KCheckThread.pas';
{$R *.res}
var
g_hInstance: Cardinal;
ModuleFilePath: AnsiString;
type
TMethodHolder = class(TObject)
public
Terminated: Boolean;
constructor Create;
procedure ThreadDone( Sender: TObject );
end;
constructor TMethodHolder.Create;
begin
Terminated := False;
inherited;
end;
procedure TMethodHolder.ThreadDone(Sender: TObject);
begin
Terminated := True;
end;
function LibInit:AnsiString;
var
buf: array[0..MAX_PATH-1] of WideChar;
R: Integer;
begin
R := GetModuleFileName( HInstance, @buf, MAX_PATH );
Result := AnsiString( buf );
end;
procedure LibraryProc(reason : Integer);
begin
g_hInstance := HInstance;
case reason of
DLL_PROCESS_ATTACH:
begin
ModuleFilePath := ExtractFilePath( LibInit );
end;
DLL_THREAD_ATTACH: ;
DLL_THREAD_DETACH: ;
DLL_PROCESS_DETACH: ;
end;
end;
function HTTPKCheck(var NoKousu:PAnsiChar): Boolean; stdcall;
var
Ret: Boolean;
KCheckThread: TKCheckThread;
MethodHolder: TMethodHolder;
begin
KCheckThread := TKCheckThread.Create( True );
MethodHolder := TMethodHolder.Create;
KCheckThread.FreeOnTerminate := False;
KCheckThread.OnTerminate := MethodHolder.ThreadDone;
KCheckThread.Resume;
repeat
Application.ProcessMessages;
Sleep( 1 );
until ( MethodHolder.Terminated );
if KCheckThread.ExecResult then
begin
StrCopy( @RetVal, PAnsiChar( KCheckThread.RetVal ) );
end;
KCheckThread.Destroy;
Result := True;
end;
exports
HTTPKCheck,
DecryptStr,
EncryptStr;
begin
DLLProc := @LibraryProc;
DLLProc( DLL_PROCESS_ATTACH );
end.
>=== スレッド側ソース
unit KCheckThread;
interface
uses
Classes {$IFDEF MSWINDOWS} , Windows {$ENDIF},
SysUtils, DateUtils, IdBaseComponent, IdComponent,
IdTCPConnection, IdTCPClient, IdHTTP, IdIOHandler, IdIOHandlerSocket,
IdIOHandlerStack, IdSSL, IdSSLOpenSSL, IdCookieManager, IdMultipartFormData,
IdAntiFreezeBase, IdAntiFreeze;
type
TKCheckThread = class(TThread)
IdHTTP:TIdHTTP;
IdSSLIOHandlerSocketOpenSSL: TIdSSLIOHandlerSocketOpenSSL;
IdCookieManager: TIdCookieManager;
IdAntiFreeze: TIdAntiFreeze;
private
{ Private 宣言 }
FRetVal: AnsiString;
FReadTimeOut: Integer;
FConnectTimeOut: Integer;
public
{ Public 宣言 }
constructor Create( CreateSuspended: Boolean );
destructor Destroy;override;
property RetVal:AnsiString read FRetVal;
property ReadTimeOut:Integer read FReadTimeOut write FReadTimeOut;
property ConnectTimeOut:Integer read FConnectTimeOut write FConnectTimeOut;
protected
procedure Execute; override;
end;
const
UserAgent = 'Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; .NET CLR 1.1.4322)';
implementation
{ TKCheckThread }
//コンストラクタ
constructor TKCheckThread.Create( CreateSuspended: Boolean );
begin
IdHTTP := TIdHTTP.Create( nil );
IdSSLIOHandlerSocketOpenSSL := TIdSSLIOHandlerSocketOpenSSL.Create( IdHTTP );
IdCookieManager := TIdCookieManager.Create( IdHTTP );
IdAntiFreeze := TIdAntiFreeze.Create( IdHTTP );
IdHTTP.IOHandler := IdSSLIOHandlerSocketOpenSSL;
IdHTTP.CookieManager := IdCookieManager;
IdHTTP.HandleRedirects := True;
IdHTTP.Request.UserAgent := UserAgent;
IdAntiFreeze.Active := True;
FReadTimeOut := 10000;
FConnectTimeOut := 3000;
IdHTTP.ProtocolVersion := pv1_1;
inherited Create( CreateSuspended );
end;
//デストラクタ
destructor TKCheckThread.Destroy;
begin
IdHTTP.Free;
inherited;
end;
procedure TKCheckThread.Execute;
begin
{IdHTTPを使ったHTTP通信処理}
{結果をFRetValに渡す}
end;
end.
--
Y.Hosoi
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
メンバーで使える掲示板を活用しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hdG3B
-----------------------------------------------------[freeml by GMO]--
細井さん:
> 現在、DelphiでDLLを作成しています。
> そのDLLの上位アプリはBCB、Delphi等で使います。
>
> DLL内でスレッド(TThread)を使用してその終わりを待ちたいのですが、
> うまくいきませんのでご教授いただければと思います。
スレッドの OnTerminate イベントで、TMethodHolder.Terminated を
True に変えることで、メインスレッドの待ちループからの脱出に利用
しているということですね。
お示しくださったソースを詳しく見ることができないのですが、一般的な
こととして、まずは TThread.Execute メソッドで、トラップされていない
例外が発生していないかご確認ください。 また TThread.Execute
メソッドが終了しているかどうかをご確認ください。 終了待ちの方法
自体には(下記の点を除いて)問題ないと思います。 DLLの内部で
あるかどうかも、特に関係しません。
なおスレッドの FreeOnTerminate は True にした方がいいと思います。
そうしないとどこかで TThread.Free を呼び出してやる必要がありますが、
それまでにスレッドの処理が終わっているとは限らない(スレッドは
OnTerminate を呼び出してからも、いろいろな後始末をします)ので、
下手をするとアクセス違反が発生します。
――――――――――――――――――――――――――――――――――――
株式会社イマジオム 代表取締役 高木太郎
〒316-0024 茨城県 日立市 水木町 1-11-10
電話:0294-28-0147
ファクシミリ:0294-28-0148
電子メール:tarou_...@imageom.co.jp
ホームページ:http://www.imageom.co.jp/
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
メールだけでみんなを招待できる便利機能♪
http://ad.freeml.com/cgi-bin/sa.cgi?id=hdHUK
ご助言有り難うございます。
|-----Original Message-----
|こんにちは、イマジオムの高木です。
|
|細井さん:
|> 現在、DelphiでDLLを作成しています。
|> そのDLLの上位アプリはBCB、Delphi等で使います。
|>
|> DLL内でスレッド(TThread)を使用してその終わりを待ちたいのですが、
|> うまくいきませんのでご教授いただければと思います。
|
| スレッドの OnTerminate イベントで、TMethodHolder.Terminated を
|True に変えることで、メインスレッドの待ちループからの脱出に利用
|しているということですね。
はい、そうです。
| お示しくださったソースを詳しく見ることができないのですが、一般的な
|こととして、まずは TThread.Execute メソッドで、トラップされていない
|例外が発生していないかご確認ください。 また TThread.Execute
|メソッドが終了しているかどうかをご確認ください。 終了待ちの方法
|自体には(下記の点を除いて)問題ないと思います。 DLLの内部で
|あるかどうかも、特に関係しません。
TThread.Execute内での例外は発生していません。
と言うか、Thread.Executeの中をほぼコメントアウトしてもダメです。
ブレークポイントをExecute内に設定してステップ実行を行っているのですが、
Executeを抜けるとどこかに行ってしまいます。
それが謎なんですよね
| なおスレッドの FreeOnTerminate は True にした方がいいと思います。
|そうしないとどこかで TThread.Free を呼び出してやる必要がありますが、
|それまでにスレッドの処理が終わっているとは限らない(スレッドは
|OnTerminate を呼び出してからも、いろいろな後始末をします)ので、
|下手をするとアクセス違反が発生します。
そうしたいのですが、TThreadからの戻り値を得たいのでFreeOnTerminateをTrue
に出来ないんです。
その場合はやはりSyncronizeを使って渡す方法が良いのでしょうか?
以上ですがよろしくお願いします。
--
Y.Hosoi
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
練習や試合の予定調整は「とっとと決め太郎」におまかせ!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hdIti
細井様:
>| スレッドの OnTerminate イベントで、TMethodHolder.Terminated を
>| True に変えることで、メインスレッドの待ちループからの脱出に利用
>| しているということですね。
>
> はい、そうです。
これ自体は問題ないと思います。 Terminated への代入はCPUの
1命令でできますから、同期を取る必要もありません。
>| まずは TThread.Execute メソッドで、トラップされていない例外が
>| 発生していないかご確認ください。 また TThread.Execute メソッドが
>| 終了しているかどうかをご確認ください。
>
> TThread.Execute内での例外は発生していません。
> と言うか、Thread.Executeの中をほぼコメントアウトしてもダメです。
そうだとすると、やはり下記の FreeOnTerminate が怪しいと思います。
あらためてお示しのコードを見ましたが、やはり待ちループを抜けて
すぐ KCheckThread を破棄なさっていて、これは非常に危険です。
> ブレークポイントをExecute内に設定してステップ実行を行っているの
> ですが、Executeを抜けるとどこかに行ってしまいます。
> それが謎なんですよね
スレッドがなくなっているので、それ自体は正しい動作だと思います。
ブレークポイントを TMethodHolder.ThreadDone に置くと、そこで
止まりませんか?
>| なおスレッドの FreeOnTerminate は True にした方がいいと思います。
>| そうしないとどこかで TThread.Free を呼び出してやる必要がありますが、
>| それまでにスレッドの処理が終わっているとは限らない(スレッドは
>| OnTerminate を呼び出してからも、いろいろな後始末をします)ので、
>| 下手をするとアクセス違反が発生します。
>
> そうしたいのですが、TThreadからの戻り値を得たいのでFreeOnTerminateを
> Trueに出来ないんです。その場合はやはりSyncronizeを使って渡す方法が
> 良いのでしょうか?
戻り値のことはひとまず置いておいて、FreeOnTerminate を True に
変え、またメインスレッドで TThread を破棄しないようにしてみて
ください(KCheckThread.Destroy をコメントアウト)。 それでも無限
ループにはまりますか?
戻り値のために Synchronize を使う必要はありません。 無限ループ
問題が解決してからお話しいたします。
――――――――――――――――――――――――――――――――――――
株式会社イマジオム 代表取締役 高木太郎
〒316-0024 茨城県 日立市 水木町 1-11-10
電話:0294-28-0147
ファクシミリ:0294-28-0148
電子メール:tarou_...@imageom.co.jp
ホームページ:http://www.imageom.co.jp/
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
友達の服をこっそり借りちゃお!「おしゃれ泥棒」OPEN!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hdJFP
重ね重ね有り難うございます。
|-----Original Message-----
|From: 高木太郎
|Sent: Thursday, Jul 28, 2011 01:28 PM
|To: delphi...@freeml.com
|
|Subject: [delphi-users:2077] Re: Re[2]: DLL内でのTThreadの終わりを知りたい
|
|こんにちは、イマジオムの高木です。
・
|>| まずは TThread.Execute メソッドで、トラップされていない例外が
|>| 発生していないかご確認ください。 また TThread.Execute メソッドが
|>| 終了しているかどうかをご確認ください。
|>
|> TThread.Execute内での例外は発生していません。
|> と言うか、Thread.Executeの中をほぼコメントアウトしてもダメです。
|
| そうだとすると、やはり下記の FreeOnTerminate が怪しいと思います。
|あらためてお示しのコードを見ましたが、やはり待ちループを抜けて
|すぐ KCheckThread を破棄なさっていて、これは非常に危険です。
了解しました。
FreeOnTerminateはTrueに設定しました。
|> ブレークポイントをExecute内に設定してステップ実行を行っているの
|> ですが、Executeを抜けるとどこかに行ってしまいます。
|> それが謎なんですよね
|
| スレッドがなくなっているので、それ自体は正しい動作だと思います。
|ブレークポイントを TMethodHolder.ThreadDone に置くと、そこで
|止まりませんか?
・
| 戻り値のことはひとまず置いておいて、FreeOnTerminate を True に
|変え、またメインスレッドで TThread を破棄しないようにしてみて
|ください(KCheckThread.Destroy をコメントアウト)。 それでも無限
|ループにはまりますか?
FreeOnTerminate := True;
//KCheck.Destroyをコメントアウト
してブレークポイントを
1、KCheckThread.Create内
2、KCheckThread.Execute内
3、KCheckThread.Destroy内
4、MethodHolder.ThreadDone内
に置いて確認したところ
1でストップ、そのまま継続実行
2でストップ、そのまま継続実行
で、あとは
repeat
Application.ProcessMessages;
Sleep( 1 );
until ( MethodHolder.Terminated );
の無限ループに入っているようで(上記にブレークポイントを設定すると止まる)
4では止まりませんでした。
もしやと思い、Indy系のコンポーネントを全てコメントアウトしてみました(要
はスレッド内での処理をほとんどやっていない)が、結果は同じでした。
上記無限ループに入っているときのKCheckThreadの状況は開始後しばらくは「走
行中」ですが、しばらく待つと「停止」になります。
以上ですがよろしくお願いします。
--
Y.Hosoi
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
戦国時代の武将達とともに天下統一を目指そう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hdKfl
細井さま:
> FreeOnTerminate := True;
> //KCheck.Destroyをコメントアウト
> してブレークポイントを
> 1、KCheckThread.Create内
> 2、KCheckThread.Execute内
> 3、KCheckThread.Destroy内
> 4、MethodHolder.ThreadDone内
> に置いて確認したところ
>
> 1でストップ、そのまま継続実行
> 2でストップ、そのまま継続実行
> で、あとは
> repeat
> Application.ProcessMessages;
> Sleep( 1 );
> until ( MethodHolder.Terminated );
> の無限ループに入っているようで(上記にブレークポイントを設定
> すると止まる)4では止まりませんでした。
FreeOnTerminate:=True でも解決しないのですね。
> Indy系のコンポーネントを全てコメントアウトしてみました(要は
> スレッド内での処理をほとんどやっていない)が、結果は同じでした。
>
> 上記無限ループに入っているときのKCheckThreadの状況は開始後
> しばらくは「走行中」ですが、しばらく待つと「停止」になります。
OnTerminate イベントが発生していないようですので、お示しの
ソースを精読してみました。 一つ気になったことがあります。
それは TKCheckThread.Create の作りです。 現状を要約すると
次のようになっています。
constructor TKCheckThread.Create;
begin
<いろいろな処理>
inherited Create(CreateSuspended);
end;
これは、次のようにした方がいいと思います。
constructor TKCheckThread.Create;
begin
inherited Create(CreateSuspended);
<いろいろな処理>
if not CreateSuspended then
Resume;
end;
まだ確認していませんが、お示しの実装だと <いろいろな処理> が
行われる前にスレッドが動いてしまう気がします。 なかなか
決定的なことが言えなくて申しわけありませんが、お試しください
ませんか。
――――――――――――――――――――――――――――――――――――
株式会社イマジオム 代表取締役 高木太郎
〒316-0024 茨城県 日立市 水木町 1-11-10
電話:0294-28-0147
ファクシミリ:0294-28-0148
電子メール:tarou_...@imageom.co.jp
ホームページ:http://www.imageom.co.jp/
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
【重要】携帯電話向けMLメールの仕様変更のお知らせ
http://ad.freeml.com/cgi-bin/sa.cgi?id=hdLhQ
|-----Original Message-----
|こんにちは、イマジオムの高木です。
・
|> repeat
|> Application.ProcessMessages;
|> Sleep( 1 );
|> until ( MethodHolder.Terminated );
|> の無限ループに入っているようで(上記にブレークポイントを設定
|> すると止まる)4では止まりませんでした。
|
| FreeOnTerminate:=True でも解決しないのですね。
はい、解決しませんでした。
|> Indy系のコンポーネントを全てコメントアウトしてみました(要は
|> スレッド内での処理をほとんどやっていない)が、結果は同じでした。
|>
|> 上記無限ループに入っているときのKCheckThreadの状況は開始後
|> しばらくは「走行中」ですが、しばらく待つと「停止」になります。
|
| OnTerminate イベントが発生していないようですので、お示しの
|ソースを精読してみました。 一つ気になったことがあります。
|それは TKCheckThread.Create の作りです。 現状を要約すると
|次のようになっています。
・
|これは、次のようにした方がいいと思います。
|
|constructor TKCheckThread.Create;
|begin
| inherited Create(CreateSuspended);
| <いろいろな処理>
| if not CreateSuspended then
| Resume;
|end;
|
|まだ確認していませんが、お示しの実装だと <いろいろな処理> が
|行われる前にスレッドが動いてしまう気がします。 なかなか
|決定的なことが言えなくて申しわけありませんが、お試しください
|ませんか。
上記に変更してみましたが、やはり結果は同じでOnTerminateイベントが発生し
ていないようです。
こちらでもそれなりにいろいろ変更しながら試しているのですが、う~ん、ダメ
なんですかねぇ
--
Y.Hosoi
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
使い方はいろいろ♪一部のメンバーだけにMLメールを送ろう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hdLJe
細井さま:
>| それは TKCheckThread.Create の作りです。 現状を要約すると
>| 次のようになっています。
> ・
>| これは、次のようにした方がいいと思います。
>|
>| constructor TKCheckThread.Create;
>| begin
>| inherited Create(CreateSuspended);
>| <いろいろな処理>
>| if not CreateSuspended then
>| Resume;
>| end;
>|
>| まだ確認していませんが、お示しの実装だと <いろいろな処理> が
>| 行われる前にスレッドが動いてしまう気がします。
>
> 上記に変更してみましたが、やはり結果は同じでOnTerminate
> イベントが発生していないようです。
>
> こちらでもそれなりにいろいろ変更しながら試しているのですが、
> う~ん、ダメなんですかねぇ
OnTerminate イベントが発生しないというのは、非常に重要な
ヒントだと思います。 その原因を考えてみると──
1.TThread.Execute が実行されていない。 Resume されて
いない。
2.TThread.Execute で、トラップされない例外が発生している。
3.TThread.OnTerminate をセットする前に Execute が実行を
終わってしまった。
4.TThread.Execute が終了しない。 無限ループにはまって
いる。
5.TThread.OnTerminate がセットされていない。 あるいは
セットした後、nil に戻している。
──といったものが考えられます。 上記のいずれかだと思うのです。
幸い再現性はありそうですので、try 文による例外トラップや
ブレークポイントを使って追い込んでいくことは可能だと思います。
私の経験では、スレッドはそんなにたちの悪いものではありません。
怪奇現象が多いですが、原因がわかれば「な~んだ」と納得するもの
ばかりです。
当方でも引き続き、お示しのソースコードを精査してみますが、上記の
ような観点で原因を探してみてはいかがでしょうか。
――――――――――――――――――――――――――――――――――――
株式会社イマジオム 代表取締役 高木太郎
〒316-0024 茨城県 日立市 水木町 1-11-10
電話:0294-28-0147
ファクシミリ:0294-28-0148
電子メール:tarou_...@imageom.co.jp
ホームページ:http://www.imageom.co.jp/
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
メンバーで使える掲示板を活用しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hdQ7z
すみません、gmailで受信されている方には先の私のメールが届いていないと思
いますので一報させていただきます。
添付ファイルのある2つのメールを添付しました(下記)
http://www.freeml.com/delphi-users/2082
http://www.freeml.com/delphi-users/2083
gmailでは添付ファイルの制限がありますのでメールすら配信されていないと思
います。
一部のファイル形式がブロックされる
https://mail.google.com/support/bin/answer.py?hl=ja&answer=6590
以上ですがよろしくお願いします。
On Thu, 28 Jul 2011 20:57:52 +0900 (JST)
高木太郎 <delphi...@freeml.com> wrote:
|こんにちは、イマジオムの高木です。
|
|細井さま:
|>| それは TKCheckThread.Create の作りです。 現状を要約すると
|>| 次のようになっています。
|> ・
--
Y.Hosoi
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
クーポンサイトを選んで検索♪一番おトクなクーポンをGET!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hdU2J
細井さま:
> 再度DLL内でTThreadを使うのではなくてTForm内でどうなるのか?
> (いわゆる通常使用)を試してみましたので添付します。
>
> 結果は
> ・DLL内だとOnTerminatedが呼ばれないみたい
> ・Exe(TForm)内だと問題なく動作する
私はDLL内でもスレッドを多用していますが、お書きのような
トラブルに遭ったことがなく、不思議な感じがします。
原因究明も続けるとして、並行して解決策を考えましょう。
まず細井さんの同期方法をまとめると次のようになります。
1.メインスレッドで TMethodHolder.Terminated フラグを監視
しながら待ちループを回す。
2.TThread.OnTerminate イベントで上記フラグをセットする。
これであれば、OnTerminate イベントや Synchronize を使わずに
できます。 TThread.Execute メソッドの終了直前に、直接 TMethod-
Holder.Terminated フラグをセットしても問題ありません。 Boolean
型への代入は、CPU命令一つでできますので、代入中に割り込まれる
心配がないからです。
ただ今のコードだと、TThread.Execute メソッドから直接 TMethod-
Holder.Terminated フラグを参照することができないと思います。
ですのでフラグへのポインタを TThread に持たせ、Execute では
ポインタの参照先(フラグ本体)をセットするのが最も簡単だと
思います。
いただいたソースも、後で実行させてみます。
――――――――――――――――――――――――――――――――――――
株式会社イマジオム 代表取締役 高木太郎
〒316-0024 茨城県 日立市 水木町 1-11-10
電話:0294-28-0147
ファクシミリ:0294-28-0148
電子メール:tarou_...@imageom.co.jp
ホームページ:http://www.imageom.co.jp/
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
友達の服をこっそり借りちゃお!「おしゃれ泥棒」OPEN!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hdVCS
細井さま:
> 再度DLL内でTThreadを使うのではなくてTForm内でどうなるのか?
> (いわゆる通常使用)を試してみましたので添付します。
>
> 結果は
> ・DLL内だとOnTerminatedが呼ばれないみたい
> ・Exe(TForm)内だと問題なく動作する
> でした。
いただいたサンプルを動かしてみたところ、当方ではDLL内でも
TThread.OnTerminate イベントが発生、ちゃんと待ちループからも
抜けてきました。 抜けるまで10[秒]くらいかかりますが、
これは予想どおりの動作です。
なお当方の環境は Delphi 5、Windows XP です。 いただいた
プログラムそのものでは動かなかったので、下記の小修正を
しましたが、プログラムの動作には関係ないはずです。
修正:libtest の本体
[修正前]
begin
DLLProc := @LibraryProc;
DLLProc( DLL_PROCESS_ATTACH );
end.
[修正後]
begin
LibraryProc(DLL_PROCESS_ATTACH);
end.
――――――――――――――――――――――――――――――――――――
株式会社イマジオム 代表取締役 高木太郎
〒316-0024 茨城県 日立市 水木町 1-11-10
電話:0294-28-0147
ファクシミリ:0294-28-0148
電子メール:tarou_...@imageom.co.jp
ホームページ:http://www.imageom.co.jp/
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
戦国時代の武将達とともに天下統一を目指そう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hdXwn
Synchronizeの中の処理はいまいち何がどうなってるのか理解出来ないんですが、
class procedure TThread.Synchronize(ASyncRec: PSynchronizeRecord);
の中のWaitForSingleObject(SyncProc.Signal, INFINITE);の呼び出しから帰ってきません。
SyncProc.Signalのイベントは、CheckSynchronizeの中でシグナル状態に設定されるみたいなので、Terminatedのループの中でCheckSynchronize(0);を呼び出すと上手く行く感じですが頻繁に呼び出して他に影響が無いのか不明なのでなんとも言えません。
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
【重要】携帯電話向けMLメールの仕様変更のお知らせ
http://ad.freeml.com/cgi-bin/sa.cgi?id=hdXPc
皆さん、有り難うございます。
|-----Original Message-----
|上村です。
|Delphi7、WinXPの環境で処理を追ってみました。
|OnTerminateの呼び出し時にSynchronizeが呼ばれるみたいなんですが、その中でデッドロック起こしてるように見えます。
・
|Synchronizeの中の処理はいまいち何がどうなってるのか理解出来ないんですが、
|class procedure TThread.Synchronize(ASyncRec: PSynchronizeRecord);
|の中のWaitForSingleObject(SyncProc.Signal, INFINITE);の呼び出しから帰ってきません。
|
|SyncProc.Signalのイベントは、CheckSynchronizeの中でシグナル状態に設定されるみたいなので、Terminatedのループの中でCheckSynchronize(0);を呼び出すと上手く行く感じですが頻繁に呼び出して他に影響が無いのか不明なのでなんとも言えません。
CheckSynchronizeと言うキーワードで検索したところ下記が見つかりました。
http://ja.w3support.net/index.php?db=so&id=272987
この方もCheckSynchronize(0);をループの中で呼んでいるみたいですね。
こちらでもCheckSynchronize(0);を追加したら想定の動作が行われました。
いろいろとありがとうございました。
--
Y.Hosoi
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
使い方はいろいろ♪一部のメンバーだけにMLメールを送ろう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hdY9z
失礼しました。
まだ、下記件が解決していなかったですね。
もし、できましたらこちらもご教授頂きたくよろしくお願いします。
|-----Original Message-----
|こんにちは、イマジオムの高木です。
・
|>| なおスレッドの FreeOnTerminate は True にした方がいいと思います。
|>| そうしないとどこかで TThread.Free を呼び出してやる必要がありますが、
|>| それまでにスレッドの処理が終わっているとは限らない(スレッドは
|>| OnTerminate を呼び出してからも、いろいろな後始末をします)ので、
|>| 下手をするとアクセス違反が発生します。
|>
|> そうしたいのですが、TThreadからの戻り値を得たいのでFreeOnTerminateを
|> Trueに出来ないんです。その場合はやはりSyncronizeを使って渡す方法が
|> 良いのでしょうか?
|
| 戻り値のことはひとまず置いておいて、FreeOnTerminate を True に
|変え、またメインスレッドで TThread を破棄しないようにしてみて
|ください(KCheckThread.Destroy をコメントアウト)。 それでも無限
|ループにはまりますか?
|
| 戻り値のために Synchronize を使う必要はありません。 無限ループ
|問題が解決してからお話しいたします。
--
Y.Hosoi
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
メンバーで使える掲示板を活用しよう!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hdYFN
細井さま:
> まだ、下記件が解決していなかったですね。
> もし、できましたらこちらもご教授頂きたくよろしくお願いします。
>| 戻り値のために Synchronize を使う必要はありません。 無限ループ
>| 問題が解決してからお話しいたします。
はい。 終了を知らせる方法については [delphi-users:2085] で
書きました。 再掲します。
> 1.メインスレッドで TMethodHolder.Terminated フラグを監視
> しながら待ちループを回す。
> 2.TThread.OnTerminate イベントで上記フラグをセットする。
>
> これであれば、OnTerminate イベントや Synchronize を使わずに
> できます。 TThread.Execute メソッドの終了直前に、直接 TMethod-
> Holder.Terminated フラグをセットしても問題ありません。 Boolean
> 型への代入は、CPU命令一つでできますので、代入中に割り込まれる
> 心配がないからです。
>
> ただ今のコードだと、TThread.Execute メソッドから直接 TMethod-
> Holder.Terminated フラグを参照することができないと思います。
> ですのでフラグへのポインタを TThread に持たせ、Execute では
> ポインタの参照先(フラグ本体)をセットするのが最も簡単だと
> 思います。
戻り値も、基本的にこれと同じやり方でできます。 つまり戻り値への
ポインタをスレッドに持たせ、TThread.Execute メソッドでポインタの
参照先に代入します。
簡単なサンプルを示します。
type TMyThread=class(TThread)
public
ResultPtr :PString;
TerminatedPtr:PBoolean;
procedure Execute; override;
end;
procedure TMyThread.Execute;
begin
<スレッド処理>
ResultPtr^:=<結果>;
TerminatedPtr^:=True; // 必ず結果を返してからフラグを立てる
end;
procedure TForm1.Button1Click;
var Terminated:Boolean;
Result :string;
begin
Thread:=TMyThread.Create(True);
Thread.FreeOnTerminate:=True;
Thread.ResultPtr :=@Result;
Thread.TerminatedPtr:=@Terminated;
Terminated:=False;
Thread.Resume; // 必ず Terminated の初期化後にスレッドを動かす
repeat
Sleep(1);
Application.ProcessMessages;
until Terminated:
ShowMessage(Result);
end;
このように同期を省いて簡単に実装することができるのは、repeat-
until 節の中では、Terminated・Result とも、このスレッドからしか
書き込まれないことが確実だからです。 Terminated の方はメイン
スレッドから読み出されることもありますが、Boolean 型はCPU
命令1個で読み書きできますので、排他制御が必要ありません。
Result は書き込み中にスレッドが切り替わる可能性があるものの、
待ちループの中ではメインスレッドから読み出されませんので、
やはり排他制御が必要ありません。
――――――――――――――――――――――――――――――――――――
株式会社イマジオム 代表取締役 高木太郎
〒316-0024 茨城県 日立市 水木町 1-11-10
電話:0294-28-0147
ファクシミリ:0294-28-0148
電子メール:tarou_...@imageom.co.jp
ホームページ:http://www.imageom.co.jp/
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
メールだけでみんなを招待できる便利機能♪
http://ad.freeml.com/cgi-bin/sa.cgi?id=hdZ0x
皆さん、ほんとうにいつもありがとうございます。
特に高木さん、ありがとうございました。
下記件の内容で目的は達成できました。
C++を使っているとポインタを意識するのですが、Delphiだとあまり意識せずに
コーディング出来てしまうので気づきませんでした。
ありがとうございました。
|-----Original Message-----
|From: 高木太郎
|Sent: Friday, Jul 29, 2011 01:42 PM
|To: delphi...@freeml.com
|
|Subject: [delphi-users:2090] Re: Re[4]: DLL内でのTThreadの終わりを知りたい
|
|こんにちは、イマジオムの高木です。
|
|細井さま:
|> まだ、下記件が解決していなかったですね。
|> もし、できましたらこちらもご教授頂きたくよろしくお願いします。
|
|>| 戻り値のために Synchronize を使う必要はありません。 無限ループ
|>| 問題が解決してからお話しいたします。
・
| 戻り値も、基本的にこれと同じやり方でできます。 つまり戻り値への
|ポインタをスレッドに持たせ、TThread.Execute メソッドでポインタの
|参照先に代入します。
・
| このように同期を省いて簡単に実装することができるのは、repeat-
|until 節の中では、Terminated・Result とも、このスレッドからしか
|書き込まれないことが確実だからです。 Terminated の方はメイン
|スレッドから読み出されることもありますが、Boolean 型はCPU
|命令1個で読み書きできますので、排他制御が必要ありません。
|Result は書き込み中にスレッドが切り替わる可能性があるものの、
|待ちループの中ではメインスレッドから読み出されませんので、
|やはり排他制御が必要ありません。
--
Y.Hosoi
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
練習や試合の予定調整は「とっとと決め太郎」におまかせ!
http://ad.freeml.com/cgi-bin/sa.cgi?id=heaPy
[Delphi-ML:69244] DLL 側で作成したスレッドでのSynchronize が動かない
http://www2.big.or.jp/~osamu/Delphi/delphi-browse.cgi?index=069244
要するに *** Delphi 6 以降 *** では、DLL内 では Synchronize が動かないんです。
最近のDelphiで動くか確認していませんが、Delphi 6/7ならこれが使えます。
ID: 21148, D6DLLSynchronizer for Delphi 6 and 7
http://cc.embarcadero.com/item/21148
hosoi さんは書きました:
----------
東京都 日野市 中村拓男
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
クーポンサイトを選んで検索♪一番おトクなクーポンをGET!
http://ad.freeml.com/cgi-bin/sa.cgi?id=hed68
中村さん、有り難うございます。
Delphi XEでも使えるようです。
D6DLLSynchronizerをプロジェクトに追加してコンパイルしただけで動作しまし
た。
取り急ぎ以上報告まで
|-----Original Message-----
|From: 中村@ブレーン
|Sent: Friday, Jul 29, 2011 06:35 PM
|To: delphi...@freeml.com
|
|Subject: [delphi-users:2092] Re: DLL内でのTThreadの終わりを知りたい
|
|中村@ブレーンです。これはかなり古くからある問題ですね。
|
|[Delphi-ML:69244] DLL 側で作成したスレッドでのSynchronize が動かない
|http://www2.big.or.jp/~osamu/Delphi/delphi-browse.cgi?index=069244
|
|要するに *** Delphi 6 以降 *** では、DLL内 では Synchronize が動かないんです。
|
|最近のDelphiで動くか確認していませんが、Delphi 6/7ならこれが使えます。
|
|ID: 21148, D6DLLSynchronizer for Delphi 6 and 7
|http://cc.embarcadero.com/item/21148
--
Y.Hosoi
MLホームページ: http://www.freeml.com/delphi-users
----------------------------------------------------------------------
友達の服をこっそり借りちゃお!「おしゃれ泥棒」OPEN!
http://ad.freeml.com/cgi-bin/sa.cgi?id=heEUG