我正在尝试利用共享函数(在主线程中)并从 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;
}
//---------------------------------------------------------------------------
问题:
- 如果我快速关闭窗口(只有一个线程执行该函数,它永远不会离开程序 - 永远等待,并且在调试器中只有第一个线程退出,其他两个不退出)。我正在使用 OnCloseQuery 事件来检查线程是否已完成。我做错了什么?
[编辑]Memo1->Lines->Add(TextData);
按照大卫赫弗南评论中的建议删除后,它正确退出,因此这部分问题得到解决,以下内容仍然存在:
像上面那样在共享函数内部调用是否可以
csShared->Enter();
,或者我必须在每个线程中调用它外部,如下所示:void __fastcall TForm1::IdThreadComponent1Run(TIdThreadComponent *Sender) { csShared->Enter(); SharedFunction("Thread 1 calling"); csShared->Leave(); IdThreadComponent1->Stop(); }
这比上面的版本更好吗(
csShared->Enter();
在函数本身内调用)?还是一样?两个版本似乎都可以正常工作,我想知道是否有区别,因为第一个版本更干净。
如果您想知道,我不需要Synchronize
,这将用于磁盘写入而不是用于更新 VCL,因此上述 SharedFunction 仅用于示例目的。