Multithreading Delphi-帮助从另一个线程调用线程dll函数

Multithreading Delphi-帮助从另一个线程调用线程dll函数,multithreading,delphi,dll,synchronize,Multithreading,Delphi,Dll,Synchronize,我使用的是Delphi2006,我正在开发的应用程序有点问题 我有一个表单,它创建了一个线程,该线程调用一个执行长操作的函数,让我们调用它LengthyProcess。在LengthyProcess函数中,我们还调用了几个Dll函数,它们也创建自己的线程 我遇到的问题是,如果我不使用线程的Synchronize函数调用LengthyProcess,线程将停止响应(主线程仍然响应良好)。我不想使用Synchronize,因为这意味着主线程正在等待LengthyProcess完成,因此无法实现创建单

我使用的是Delphi2006,我正在开发的应用程序有点问题

我有一个表单,它创建了一个线程,该线程调用一个执行长操作的函数,让我们调用它LengthyProcess。在LengthyProcess函数中,我们还调用了几个Dll函数,它们也创建自己的线程

我遇到的问题是,如果我不使用线程的Synchronize函数调用LengthyProcess,线程将停止响应(主线程仍然响应良好)。我不想使用Synchronize,因为这意味着主线程正在等待LengthyProcess完成,因此无法实现创建单独线程的目的

我已经跟踪到了dll中的一个函数,该函数创建了一个线程,然后调用WaitFor,顺便说一下,这都是使用TThread完成的。WaitFor检查CurrentThreadID是否等于MainThreadID,如果等于,则调用CheckSynchronization,一切正常。因此,如果我们使用Synchronize,那么CurrentThreadID将等于MainThreadID,但是如果我们不使用Synchronize,那么当然是CurrentThreadID MainThreadID,当这种情况发生时,WaitFor会告诉当前线程(我创建的线程)等待DLL创建的线程,因此永远不会调用CheckSynchronization,而我的线程将永远等待DLL中创建的线程

我希望这是有道理的,对不起,我不知道有什么更好的方式来解释它。还有其他人遇到过这个问题并且知道如何解决它吗?

如果您的辅助线程“停止响应”,那么我假设它有一个消息泵。(否则,您需要解释它停止响应的原因。)您似乎还希望线程能够检测到第三线程何时完成运行。(这里的“主”线程是VCL线程,它根本不涉及。)

您尝试使用
WaitFor
,但当发现它阻塞时,您感到失望。然而,这正是它一直被设计用来做的。它在主线程中的行为会变得很奇怪,因此从VCL线程调用是安全的,尽管它本来就不打算这样使用

要处理消息并等待线程完成运行,您需要使用Windows API中的一个或多个线程。首先。它可以等待各种类型的内核句柄,包括线程句柄,但也可以在消息可用时通知您。其思想是在循环中调用该函数。当它说消息可用时,处理它们,然后再次循环以继续等待

以下只是一个提纲。您需要检查文档中使用的所有API函数,并将其与您关于自己线程的其他知识结合起来

procedure TSecondaryThread.Execute;
var
  ret: DWord;
  ThreadHandle: THandle;
  Msg: TMsg;
begin
  ThreadHandle := TertiaryThread.Handle;
  repeat
    ret := MsgWaitForMultipleObjects(1, ThreadHandle, False, Infinite, qs_AllEvents);
    case ret of
      Wait_Object_0: begin
        // The thread terminated. Do something about it.
        CloseHandle(ThreadHandle);
        PostQuitMessage(0);
        // Put *something* in the parameter so further calls to MWFMO
        // will have a valid handle. May as well use a handle to something
        // that will never become signaled so all we'll get are more
        // messages. I'm pretty sure you can't pass an empty array of
        // handles; there must be at least one, and it must be valid.
        ThreadHandle := Self.Handle;
      end;
      Wait_Object_0 + 1: begin
        // At least one message is available. Handle *all* of
        // them before calling MsgWaitForMultipleObjects again
        while PeekMessage(Msg, 0, 0, 0, pm_Remove) do
        case Msg.Message of
          wm_Quit: begin
            // Do something about terminating the tertiary thread.
            // Then stop the message loop and the waiting loop.
            Exit;
          end;
          else begin
            TranslateMessage(Msg);
            DispatchMessage(Msg);
          end;
        end;
      end;
      Wait_Timeout: Assert(False, 'Infinity has passed');
      Wait_Failed: RaiseLastOSError;
      else Assert(False, 'Unexpected return value');
    end;
  until False;
end;
关于处理所有消息的部分很重要。只要您调用
GetMessage
PeekMessage
WaitMessage
,操作系统就会将队列中的所有消息标记为“旧”,但
MsgWaitForMultipleObjects
仅在有“新”消息时才会返回队列上的消息-在最后一次调用
PeekMessage

之后到达的消息,如果您的辅助线程“停止响应”,那么我假设它有一个消息泵。(否则,您需要解释它停止响应的原因。)您似乎还希望线程能够检测到第三线程何时完成运行。(这里的“主”线程是VCL线程,它根本不涉及。)

您尝试使用
WaitFor
,但当发现它阻塞时,您感到失望。然而,这正是它一直被设计用来做的。它在主线程中的行为会变得很奇怪,因此从VCL线程调用是安全的,尽管它本来就不打算这样使用

要处理消息并等待线程完成运行,您需要使用Windows API中的一个或多个线程。首先。它可以等待各种类型的内核句柄,包括线程句柄,但也可以在消息可用时通知您。其思想是在循环中调用该函数。当它说消息可用时,处理它们,然后再次循环以继续等待

以下只是一个提纲。您需要检查文档中使用的所有API函数,并将其与您关于自己线程的其他知识结合起来

procedure TSecondaryThread.Execute;
var
  ret: DWord;
  ThreadHandle: THandle;
  Msg: TMsg;
begin
  ThreadHandle := TertiaryThread.Handle;
  repeat
    ret := MsgWaitForMultipleObjects(1, ThreadHandle, False, Infinite, qs_AllEvents);
    case ret of
      Wait_Object_0: begin
        // The thread terminated. Do something about it.
        CloseHandle(ThreadHandle);
        PostQuitMessage(0);
        // Put *something* in the parameter so further calls to MWFMO
        // will have a valid handle. May as well use a handle to something
        // that will never become signaled so all we'll get are more
        // messages. I'm pretty sure you can't pass an empty array of
        // handles; there must be at least one, and it must be valid.
        ThreadHandle := Self.Handle;
      end;
      Wait_Object_0 + 1: begin
        // At least one message is available. Handle *all* of
        // them before calling MsgWaitForMultipleObjects again
        while PeekMessage(Msg, 0, 0, 0, pm_Remove) do
        case Msg.Message of
          wm_Quit: begin
            // Do something about terminating the tertiary thread.
            // Then stop the message loop and the waiting loop.
            Exit;
          end;
          else begin
            TranslateMessage(Msg);
            DispatchMessage(Msg);
          end;
        end;
      end;
      Wait_Timeout: Assert(False, 'Infinity has passed');
      Wait_Failed: RaiseLastOSError;
      else Assert(False, 'Unexpected return value');
    end;
  until False;
end;

关于处理所有消息的部分很重要。只要您调用
GetMessage
PeekMessage
WaitMessage
,操作系统就会将队列中的所有消息标记为“旧”,但
MsgWaitForMultipleObjects
只有在队列上有“新”消息时才会返回,该消息是在上次调用
PeekMessage
之后到达的,谢谢你的回答,是的,我知道我的问题不是很清楚,有点混乱;因此,我将尝试澄清一些事情,接下来

下面描述的所有线程都是从TThread派生的

我有一个表单,它启动一个线程,但不等待它。表单启动的线程调用执行长任务的函数

函数调用DLL中的另一个函数,DLL中的函数启动一个线程并等待它。由DLL函数启动的线程通过synchronize调用另一个函数

表单->启动线程但不等待->线程调用函数->函数调用DLL函数->DLL函数启动线程并等待->由DLL函数启动的线程通过同步调用另一个函数,即同步(更新记录)

问题是,同步调用从未返回,因为从我所看到的,它已经进入某种死锁

同步工作原理:synchronize将方法调用放入队列并设置事件,synchronize然后等待事件发出信号。当