1

我有一个 TThread 的后代和一个对象列表,每个对象都有自己的此类线程的副本以及使用 CreateEvent() API 创建的 Event 对象。

不同的对象通过事件触发相互交互。即每个线程必须等到某个其他线程将触发它的事件。当然,有一个“主”线程,它永久工作,因此永远不会发生自阻塞。该系统在每个对象中的 Execute 方法结束之前都可以正常工作。

当我试图中断所有线程时出现问题,例如通过应用程序关闭。在这种情况下,我需要一些调用每个线程的 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() ......

4

1 回答 1

1

而不是WaitForSingleObject你应该使用WaitForMultipleObjects无限超时并等待两个事件,你的 FLayer.FEvent 和第二个终止事件。

AFAIR 你必须为每个进程创建一个终止事件。如果 WaitForMultipleObjects 返回终止事件的 ID,则退出循环。

在 OnClose() 方法中,您必须简单地发出所有终止事件的信号。

于 2010-12-17T20:44:31.017 回答