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中创建的线程.
我希望这是有道理的,抱歉,我不知道有什么更好的解释方法.有没有其他人有这个问题,知道如何解决它吗?
如果你的辅助线程"停止响应",那么我认为它有一个消息泵.(否则,您需要解释它停止响应的内容.)您似乎也希望线程能够检测到第三个线程何时完成运行.(这里的"主要"线程是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.