0

我想用 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

4

2 回答 2

1

最明显的解释是:

  1. 主线程在处理消息之前已经终止。
  2. 主线程没有抽出它的消息队列。
  3. 主线程在处理消息之前销毁窗口。

如果您展示了 SSCCE,我可以进一步缩小范围。由于我们看不到 SSCCE,这意味着您需要缩小范围。

于 2013-11-14T14:10:29.657 回答
1

更新:

Sertac 找到了您的问题的原因。在应该是 a (或其他东西)fMsgHandlerHWND的构造中创建后立即被销毁。try/finallytry/except

无论如何,我的其余答案将不太容易出错。


如果没有产生您观察的测试用例,很难说出您的代码有什么问题。

但是,我建议使用更简单的方法来处理线程关闭。

在启动线程之前,为OnTerminate属性分配一个事件处理程序。通过设置TThread.FreeOnTerminate,您不必显式释放线程对象。

OnTerminate事件处理程序中,只需从线程(如果有)收集数据并将线程引用设置为 nil。

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;
于 2013-11-15T11:24:15.480 回答