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

clo*_*if3 1 delphi dll multithreading synchronize

我正在使用Delphi 2006,并且我正在开发的应用程序有点问题.

我有一个表单创建一个线程,调用一个执行冗长操作的函数,让我们称之为LengthyProcess.在LengthyProcess函数内部,我们还调用了几个Dll函数,这些函数也创建了自己的线程.

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

我已经将问题跟踪到了创建线程然后调用WaitFor的dll中的函数,顺便说一下,这都是使用TThread完成的.WaitFor检查CurrentThreadID是否等于MainThreadID,如果是,那么它将调用CheckSychronization,一切正常.因此,如果我们使用Synchronize,那么CurrentThreadID将等于MainThreadID,但是如果我们不使用Synchronize当然是CurrentThreadID <> MainThreadID,并且当发生这种情况时WaitFor会告诉当前线程(我创建的线程)等待由此创建的线程DLL等所以CheckSynchronization永远不会被调用,我的线程最终会等待dll中创建的线程.

我希望这是有道理的,抱歉,我不知道有什么更好的解释方法.有没有其他人有这个问题,知道如何解决它吗?

Rob*_*edy 7

如果你的辅助线程"停止响应",那么我认为它有一个消息泵.(否则,您需要解释它停止响应的内容.)您似乎也希望线程能够检测到第三个线程何时完成运行.(这里的"主要"线程是VCL线程,根本不涉及.)

你尝试过使用过WaitFor,但是当你发现它阻塞时却很失望.不过,这就是它一直以来的设计目标.它在主线程中的行为是它变得奇怪的地方,所以从VCL线程调用是安全的,即使它原本从来没有真正意义上使用过.

要处理消息等待线程完成运行,您需要使用Windows API中的一个或多个等待函数.从开始MsgWaitForMultipleObjects.它可以等待各种类型的内核句柄,包括线程句柄,但也可以在消息可用时通知您.这个想法是你将循环调用该函数.当它显示消息可用时,处理它们,然后再次循环以继续等待.

以下只是一个大纲.您需要查看所使用的所有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;
Run Code Online (Sandbox Code Playgroud)

处理所有消息的部分很重要.一旦你打电话GetMessage,PeekMessage或者WaitMessage,操作系统会将队列中的所有消息标记为"旧",但MsgWaitForMultipleObjects只有在队列中有"新"消息时才会返回 - 该消息是在最后一次呼叫之后到达的消息PeekMessage.