背景:我需要检查一堆网络驱动器或远程计算机是否可用.由于每个都DirectoryExists()需要大量时间直到潜在的超时,我在单独的线程中执行检查.最终用户可能会在某些检查仍在运行时关闭应用程序.由于DirectoryExists()块,我没有机会使用经典while not Terminated方法.
procedure TMyThread.Execute;
begin
AExists := DirectoryExists(AFilepath);
end;
Run Code Online (Sandbox Code Playgroud)
问题1:当应用程序退出时,某些线程是否仍在运行是否存在问题?Windows会简单地整理一下我就是这样吗?在IDE内部,我收到了未释放对象的通知,但在IDE之外它似乎很平静.
问题2:在这种情况下是否有可能终止这样的简单线程TerminateThread或者这可能是有害的?
问题3:我通常从OnTerminate()事件中的线程获取结果,然后让线程FreeOnTerminate.如果我想自己释放它们,我什么时候应该这样做?我可以在它的OnTerminate事件中释放一个线程,或者这有点太早了?一个线程如何通知我,如果没有,它会被完成OnTerminate?
我只有有限的线程经验。我想并行读取一些基本的数据库表,我需要等到所有表都被读取后才能合理地进行程序。在这方面,阻塞主线程对我来说是可以的。
此代码(简化)工作正常:
procedure ReadDBMultiThread;
var ATasks : Array of ITask;
begin
SetLength(ATasks, 3);
ATasks[0] := TTaskCreate(procedure() begin DB_ReadTable1; end);
ATasks[1] := TTaskCreate(procedure() begin DB_ReadTable2; end);
ATasks[2] := TTaskCreate(procedure() begin DB_ReadTable3; end);
ATasks[0].Start;
ATasks[1].Start;
ATasks[2].Start;
TTask.WaitForAll(ATasks);
end;
Run Code Online (Sandbox Code Playgroud)
但是,假设我想更新主窗体以显示进度,即已读取哪个数据库表(或执行任何其他必要的主线程工作)。显然,我不能使用 Synchronise(),因为这会导致 WaitForall() 死锁,我不能使用 Queue(),因为它会在 WaitForAll() 完成后执行。
那么,有没有好的解决方案来解决这种“WaitForAll vs Synchronise”的情况?我想,这一定是很多人遇到的情况……需要等待全部完成,但又想更新主线程……
我想过这样的事情,用伪代码给出,替换 WaitForAll() 语句:
repeat
Applicaton.ProcessMessages; // or "ProcessSynchroniseMessages"
until "AllTaskCompleted"(ATasks);
Run Code Online (Sandbox Code Playgroud)
这行得通吗?有更好的解决方案吗?
我可以编写像 ProcessMessages 这样的自己的例程,但仅限于同步消息,即其他主窗体事件直到稍后才会执行吗?
提前谢谢了!
我有一个问题,关于Thread在其生命周期开始时缺少消息队列.MSDN解释道
发布消息的线程必须已创建消息队列,否则对PostThreadMessage的调用将失败.使用以下方法之一来处理这种情况:
(1)调用PostThreadMessage.如果失败,请调用Sleep函数并再次调用PostThreadMessage.重复,直到PostThreadMessage成功.
(2)创建一个事件对象,然后创建该线程.在调用PostThreadMessage之前,使用WaitForSingleObject函数等待事件设置为信号状态.在要将消息发布到的线程中,调用
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE)以强制系统创建消息队列.设置事件,以指示线程已准备好接收已发布的消息.
方法(1)解决了我的问题,第二次调用PostThreadMethod()总是在我的应用程序中成功.
但是,我想理解第二种方法并且根本不理解"事件对象"(当然不是正常的Delphi事件?)"以信号状态"和"设置事件指示".
问题:有人可以将段落(2)翻译成一个简短的Delphi代码示例吗?