(メインスレッドで) 共有関数を利用し、3 つのスレッドから使用しようとしています。この関数は、ディスクへの書き込みなどの潜在的に時間のかかる操作を実行し、起こりうる問題を回避するためにロックします。私はインディIdThreadComponent
とTCriticalSection
. これがどのように見えるかです:
//---------------------------------------------------------------------------
// In header file
//---------------------------------------------------------------------------
boost::scoped_ptr<TCriticalSection> csShared;
//---------------------------------------------------------------------------
// Main file
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner)
{
csShared.reset(new TCriticalSection);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::SharedFunction(UnicodeString TextData)
{
try
{
csShared->Enter(); // As suggested by Remy this is placed incorrectly and needs to be moved outside of try block
//Memo1->Lines->Add(TextData); // [EDIT] calling this within thread is wrong
Sleep(2000);
}
__finally
{
csShared->Leave();
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdThreadComponent1Run(TIdThreadComponent *Sender)
{
SharedFunction("Thread 1 calling");
IdThreadComponent1->Stop();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdThreadComponent2Run(TIdThreadComponent *Sender)
{
SharedFunction("Thread 2 calling");
IdThreadComponent2->Stop();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::IdThreadComponent3Run(TIdThreadComponent *Sender)
{
SharedFunction("Thread 3 calling");
IdThreadComponent3->Stop();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
IdThreadComponent1->Start();
IdThreadComponent2->Start();
IdThreadComponent3->Start();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormCloseQuery(TObject *Sender, bool &CanClose)
{
// Note - these 3 Stop() calls are used if threads are set to run infinitely
// But in this example it is not needed as they stop themselves
//IdThreadComponent1->Stop();
//IdThreadComponent2->Stop();
//IdThreadComponent3->Stop();
// Now wait for lock to be released [WRONG - COMMENTED IN EDIT]
//while (!csShared->TryEnter())
// {
// Sleep(500);
// }
//csShared->Leave();
// [EDIT v1] easier and faster way to wait than above
//csShared->Enter();
//csShared->Leave();
// [EDIT v2] block exit until all threads are done
while (IdThreadComponent1->Active || IdThreadComponent2->Active || IdThreadComponent3->Active)
{
Sleep(200); // make wait loop less CPU intensive
};
CanClose = true;
}
//---------------------------------------------------------------------------
問題点:
- ウィンドウをすばやく閉じた場合 (関数を実行するスレッドは 1 つだけで、プログラムから離れることはありません。永遠に待機し、デバッガーでは最初のスレッドのみが終了し、他の 2 つのスレッドは終了しません)。スレッドが完了したかどうかを確認するために OnCloseQuery イベントを使用しています。私が間違っていることは何ですか?
[編集] Memo1->Lines->Add(TextData);
David Heffernanのコメントで提案されているように削除した後、問題のこの部分が解決され、以下が残るように適切に終了します:
上記のように共有関数内で呼び出し
csShared->Enter();
ても問題ありませんか、それとも次のように各スレッドの外部で呼び出す必要がありますか?void __fastcall TForm1::IdThreadComponent1Run(TIdThreadComponent *Sender) { csShared->Enter(); SharedFunction("Thread 1 calling"); csShared->Leave(); IdThreadComponent1->Stop(); }
これは上記のバージョン (
csShared->Enter();
関数内で呼び出す) よりも優れていますか? それとも同じ?どちらのバージョンも問題なく動作しているようですが、最初のバージョンの方がクリーンであるため、違いがあるのではないかと思います。
これはディスク書き込み用であり、VCL の更新用ではないSynchronize
ため、上記の SharedFunction は単なる例です。