私のアプリケーションはtcp/ipサーバーであり、メインスレッドは1回だけ作成され、常にリッスンしています。新しいクライアントが接続すると、メインスレッドはそのタイプの新しいスレッドを作成しますTClientThread
。ただし、実行中のクライアントスレッドのリストはありません。これは、アプリが少し複雑になるためです。スレッドがビジー(私の場合は「ビジー」)であっても、すべてのスレッドで「terminate」メソッドを実行する方法はありますか。タイムアウトセットが約30秒であるデータを待機していることを意味します...したがって、待機せずにとにかくデータを強制終了する必要があります。)?単純なクローズアプリケーションは、スレッドで「終了」メソッドを実行していないようです。これにより、FastMMによってメモリリークが報告されます...
3 に答える
シャットダウン時のメモリリークについて心配する必要はありません。オペレーティングシステムに制御を戻す前にメモリを解放するという問題が発生すると、時間の無駄になり、アプリケーションの終了が不必要に遅くなります。本当に必要なのは、すべてのデータが保存され、すべてのプロセス間ハンドル(セマフォやミューテックスなど)が正しく解放されて終了することです。
クライアントに通知するためにできる最善のことは、次のような戦略です。
- すべてのクライアント処理スレッドをどこかのリストに追加します(作成、破棄、反復を適切にロックします)
TEvent
サーバーがシャットダウンしている場合は、クライアントスレッドを終了時にリストから削除し、リストから削除された最後のアイテムにイベント(SyncObjsなどの手動リセットイベント)を設定させます。- ポーリング(たとえば
select
、タイムアウトを伴う同等のもの)または他の種類の中断(たとえば、SO_RCVTIMEO / SO_SNDTIMEO)を、他の方法では長時間実行されるブロッキングルーチンに導入し、終了したプロパティを監視します - シャットダウン時に、リストをロックして繰り返し処理し、を呼び出してから
Terminate
、イベントが通知されるのを待ちます。もちろん、リストにアイテムを追加するリスニングソケットは、リストを反復処理する前に閉じて、閉じていることがわかっている必要があります。
そのリンクをクリックすると表示される内容:
Delphiでのセマフォの使用、パート2:接続プール
投稿者:Cary Jensen
要約:セマフォは、複数のスレッドとプロセスを調整するために使用されます。セマフォが複数のスレッドに共有リソースへの同時アクセスを提供することは、この記事で説明するTFixedConnectionPoolクラスによって強調されています。
KillThreadList:TListグローバルを使用します。私は自分のスレッドでそれを次のように監視しています:
while (Not Terminated) do
begin
inc(Inker);
if (WaitForSingleObject(FTick, finterval) = WAIT_TIMEOUT) then
Begin
if Inker >= 10 then
Begin
ProcessTables;
Inker := 0;
sleep(1000);
End;
if KillThreadList.Contains(ThreadID) = True then Terminate;
End;
end;
また、プロセスでKillThreadListをテストして、安全な場所で完了する前にオプトアウトできるようにします。
OnTerminateイベントをメインスレッドに渡し、そこでKillListからThreadIDを削除します。私はこのモデルを広く使用していますが、まだ失敗していません。
procedure TfrmProcessQualcommLocations.OnTerminateThread;
var
ThreadID : Cardinal;
i : integer;
aStatusBar :TStatFrame;
begin
ThreadID := (Sender as Tthread).ThreadID;
for i := 0 to StatusBarList.Count -1 do
Begin
if StatusBarList.Items[i].ThreadID = ThreadID then
Begin
aStatusBar := StatusBarList.Items[i];
KillThreadList.Extract(ThreadID);
StatusBarList.Extract(aStatusBar);
aStatusBar.Free;
break;
End;
End;
self.Refresh;
end;
上記の場合、私はいくつかのGUIのものも削除しています。
お役に立てば幸いです。SpringerRider