2009-11-23 26 views
6

私は、ユーザーがさまざまなシステムで実行できる一連のクエリを選択できるアプリケーション(Delphi 2009を使用)を作成しました。クエリを同時に実行できるようにするために、各クエリはTADOQueryオブジェクトを使用して独自のスレッドで実行されます。これはすべて正常に動作します。マルチスレッド(TThread)Delphiアプリケーションが終了しない

問題は、クエリが実行されている(したがって、別のスレッドがアクティブである)ときにアプリケーションを閉じるときです。私は各スレッドを作成するときに、スレッドのTHandleを配列に記録します。アプリケーションを終了しようとすると、スレッドがまだ実行中であれば、スレッドのハンドルを取得し、TerminateThreadに渡します。これは理論的にはスレッドを終了し、アプリケーションを閉じることができます。しかし、これは起こりません。メインフォームのonCloseイベントがトリガされ、アプリケーションが終了しているように見えますが、プロセスはアクティブのままで、アプリケーションがまだ実行中であるかのように表示されます(つまり、「実行」ボタンがグレー表示され、デバッグビューがアクティブなど)。手動でプロセスを終了するまで(DelphiのCtrl-F2またはタスクマネージャを使用して)、コントロールをDelphiに戻すことはできません。

私はTerminateThreadを使用していますが、クエリが実行に長時間かかることがあります(エンドユーザー環境で完璧に可能な100万レコードを扱う場合は数分です)。私が間違っていない限り、スレッドはTerminatedプロパティをチェックすることができないので、クエリが返されるまでTrueに設定されていれば終了することができないため、スレッドを終了できません通常の方法で(つまり、Terminatedプロパティをチェックすることによって)大量のクエリが実行されている間にユーザーがアプリケーションを終了したい場合があります。その場合、すべてのクエリが完了するまで待つのではなく、すぐに終了する(つまり、実行中のすべてのスレッドがただちに終了する)必要があります。 TerminateThreadは理想的ですが、実際にスレッドを終了させて​​いるわけではありません!

誰でも助けてもらえますか?誰もTerminateThreadが正しく動作しない理由を知っていますか?誰もすぐに大規模なADOクエリを実行しているスレッドを取得するために何かを提案することはできますか?

ありがとうございました!

答えて

8

OnFetchProgressイベントをフックし、Eventstatus変数をesCancelに設定することで、ADOクエリを取り消すことができます。これにより、クエリが終了し、TerminateThreadを使用せずにスレッドを正常に閉じることができるようになります。

+0

これは前進のようです。私は過去1週間ほど何か他のことに取り組んできましたが、今後数日でこれを調べます。これのためのソースの例がありますか? – Jeedee

5

TerminateThreadを使用してmsdnで読むことは危険です。

のTerminateThreadは 最も極端な例で使用されなければならない危険な 機能です。あなたは あなたがターゲットスレッドが やっている を正確に知っている場合にのみのTerminateThreadを呼び出す必要があり、そしてあなたは、ターゲットスレッドはおそらく が 終了の時点で実行することができることをコード のすべてを制御します。

しかし、スレッドを殺すにも非常に効果的です。あなたはあなたの結論が正しいと確信していますか?多分、スレッドは強制終了されますが、別のスレッドはまだ実行されていますか?多分あなたのハンドルはスレッドハンドルではありませんか?いくつかのコードを表示できますか?それとももっと良い:私たち自身のために試すことができる小さな実例?

+0

を私はのTerminateThreadの使用に関する警告を認識してんだけど、上記のことを行うための私の理由を説明しました。クエリを実行するためにスレッドが起動されていないときはアプリケーションが正常終了しますが、スレッドが1つ実行されているときには終了しないため、問題の原因となっているクエリスレッドは間違いありません。 私はクエリスレッドを作成し、このような配列にハンドルを格納します。 newThread:= TQueryThread.create(true); threadStatusArr [インデックス] .threadHandle:= newThread.handle; newthread.resume; その後、配列からハンドルを取得し、TerminateThreadに渡します。 – Jeedee

6

TADOQueryでスレッドを使用する代わりに、ADOの非同期オプションの使用を検討する必要があります。その後

ADOQuery1.ExecuteOptions := [eoAsyncExecute, eoAsyncFetch, eoAsyncFetch]; 

たときに、アプリケーションの近くに、あなたが呼び出すことができます。

ADOQuery1.cancel; 
+0

私はすでにスレッドを使ってアプリケーションを書いています。残念なことに、これを行うためにクエリを書き直すには時間がかかり過ぎて、とにかくそれがほしいと思う方法がうまくいくかどうかはわかりません。 – Jeedee

関連する問題