我有一个TThread的后代和一个对象列表,每个对象都有自己的这种线程的副本,而Event对象是用CreateEvent()API创建的。
不同的对象通过事件触发相互交互。即每个线程必须等到其他线程触发其事件。当然,有一个“主”线程,它永久工作,所以永远不会发生自我阻塞。这个系统在每个对象的Execute方法结束时都可以正常工作。
当我试图中断所有线程时出现probkem,例如通过app关闭。在这种情况下,我需要一些调用每个线程的Terminate方法的外部函数:
for i := 0 to FLayers.Count - 1 do
begin
FLayers.Layer[i].FTerminating := true;
f := true;
while f do
begin
f := FLayers.Layer[i].IsActive;
if f then
begin
Sleep(100);
Application.ProcessMessages;
end;
end;
FLayers.Layer[i].FTerminating := false;
end;
此函数位于Form.OnClose()事件中。
问题是大约有两个线程正常终止,但其他所有线程都在WaitForSingleObject()调用中停止:
procedure TLayerThread.Execute;
begin
FLayer.FIsActive := true;
...............
repeat
//
if Terminated or
FLayer.FTerminating or
(FLayer.FEvent = INVALID_HANDLE_VALUE) then
begin
break;
end;
//
Fres := WaitForSingleObject(FLayer.FEvent, 100); <<<<<<<<<<<<<<<<<<<<<<<<
until Fres <> WAIT_TIMEOUT;
...........
FLayer.FIsActive := false;
end;
所有线程只是停止(挂起)在该行。尽管已设置超时值,但仍标记在上面。
有什么想法吗?
使用的是Delphi 7和Win XP。
提前致谢。
跟进 -
我发现在Execute()方法中的Synchronize()调用中涵盖了这个问题。我无法理解这里有什么问题。 Synchronize()调用通常的东西,如可视控件更新,仅此而已。
正如调试器所示,我的线程中没有一个挂在WaitForSingleObject()调用上,但这不是我在Execute()方法中用来协调不同线程,而是另一个调用。我可以假设它在这里:
class procedure TThread.Synchronize(ASyncRec: PSynchronizeRecord);
.................
LeaveCriticalSection(ThreadLock);
try
WaitForSingleObject(SyncProc.Signal, INFINITE);<<<<<<<<<<<<<<<<<<<<<<
finally
EnterCriticalSection(ThreadLock);
end;
..................
那里有人,谁可以告诉我我的代码有什么问题?我从未听说过不允许在Execute()方法中调用Synchronize()...
答案 0 :(得分:1)
而不是 WaitForSingleObject ,你应该使用带有无限超时的 WaitForMultipleObjects 并等待两个事件,即你的FLayer.FEvent和第二个终止事件。
AFAIR您必须为每个进程创建一个终止事件。 如果WaitForMultipleObjects返回终止事件的ID,则退出循环。
在OnClose()方法中,您只需要发出所有终止事件的信号。