我想将postmessage()的消息发送到TObject实例,但是在线程终止后,程序不会进入方法HandleThreadCompletion。
const
WM_THREAD_COMPLETE = WM_USER + 5437;
TObject实例(TMaster)包含线程对象的标识符
type
TMaster = class(TObject)
private
...
Fslave_search_thread : Tsrch_slave_thread;
fMsgHandlerHWND : HWND;
function start_slvsearch_th: integer;
procedure HandleThreadCompletion(var Message: TMessage);
...
public
...
end;
constructor TMaster.Create (aNode: TTreeNode; aName, anIP, aMAC: string);
begin
...
fMsgHandlerHWND := AllocateHWnd(HandleThreadCompletion);
...
end;
我在TMaster.HandleThreadCompletion()
中释放并取消线程procedure TMaster.HandleThreadCompletion(var Message: TMessage);
begin
if message.msg = WM_THREAD_COMPLETE then begin
if Assigned(Fslave_search_thread) then
begin
Fslave_search_thread.WaitFor;
Fslave_search_thread.Free;
Fslave_search_thread := nil;
...
end
end else
message.result := DefWindowProc(fMsgHandlerHWND, Message.Msg, Message.wParam, Message.lParam) ;
end;
在这里创建线程(暂停),填写一些字段而不是启动它(恢复)。
function TMaster.start_slvsearch_th: integer;
var
i: integer;
begin
if not Assigned(Fslave_search_thread) then begin
...
Fslave_search_thread := Tsrch_slave_thread.Create(true);
...
with Fslave_search_thread do
begin
master := self;
master_HWND := self.fMsgHandlerHWND;
FreeOnTerminate := False;
Resume;
...
end;
end;
终止时(从外部设置终止标志或循环结束),发送消息:
procedure Tsrch_slave_thread.Execute;
begin
while master.CMD_LISTCNT = 1 do
begin
...
if terminated then break;
end;
PostMessage(master_HWND, WM_THREAD_COMPLETE, 0, 0);
...
end;
http://members.upclive.hu/ikt/thread_terminate_test_postmessage.zip
答案 0 :(得分:1)
最明显的解释是:
如果您展示了SSCCE,我可以进一步缩小它。由于我们看不到SSCCE,这意味着你需要缩小它。
答案 1 :(得分:1)
<强>更新强>
Sertac找到了解决问题的原因。 fMsgHandlerHWND
在try/finally
构造中创建后应立即销毁try/except
,该构造应为OnTerminate
(或其他内容)。
无论如何,我的答案的其余部分不太容易实现。
如果没有产生观察结果的测试用例,很难说你的代码有什么问题。
但是,我建议使用更简单的方法来处理线程关闭。
在启动线程之前,为TThread.FreeOnTerminate
属性分配一个事件处理程序。
通过设置OnTerminate
,您不必显式释放线程对象。
在type
TMaster = class
private
FThread: TMyThread;
procedure OnThreadTerminate(Sender: TObject);
public
constructor Create;
procedure StopThread;
function StartThread: Boolean;
end;
constructor TMaster.Create;
begin
Inherited;
FThread := Nil;
end;
procedure TMaster.StopThread;
begin
if Assigned(FThread) then
FThread.Terminate;
end;
procedure TMaster.OnThreadTerminate(Sender: TObject);
begin
// Collect data from the thread
...
// Just clear the thread reference
FThread := Nil;
end;
function TMaster.StartThread: Boolean;
begin
Result := (FThread = Nil);
if Result then
begin
FThread := TMyThread.Create(True);
FThread.FreeOnTerminate := True; // Thread will self destruct
FThread.OnTerminate := Self.OnThreadTerminate; // Called when thread is terminating
FThread.Start; // Older Delphi versions uses Resume
end;
end;
事件处理程序中,只需从线程中收集数据(如果有的话),并将线程引用设置为nil。
{{1}}