加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – 等待TThread实例启动的正确方法是什么

发布时间:2020-12-15 04:22:32 所属栏目:大数据 来源:网络整理
导读:在TThread实例创建和启动之间,主线程将继续执行代码.如果主线程中的代码依赖于有问题的线程完全启动并运行它必须以某种方式等待,直到线程Execute方法实际启动. 考虑以下代码: const WM_MY_ACTION = WM_APP + 10;type TWndThread = class(TThread) protected
在TThread实例创建和启动之间,主线程将继续执行代码.如果主线程中的代码依赖于有问题的线程完全启动并运行它必须以某种方式等待,直到线程Execute方法实际启动.

考虑以下代码:

const
  WM_MY_ACTION = WM_APP + 10;

type
  TWndThread = class(TThread)
  protected
    fWndHandle: THandle;
    IsRunning: boolean;
    procedure WndProc(var Msg: TMessage);
    procedure Execute; override;
  public
    Test: integer;
    procedure AfterConstruction; override;
    procedure DoAction;
  end;

procedure TWndThread.AfterConstruction;
begin
  inherited;
  while not IsRunning do Sleep(100); // wait for thread start up
end;

procedure TWndThread.Execute;
var
  Msg: TMsg;
begin
  fWndHandle := AllocateHWnd(WndProc);
  IsRunning := true;
  try
    while not Terminated do
      begin
        if MsgWaitForMultipleObjects(0,nil^,False,1000,QS_ALLINPUT) = WAIT_OBJECT_0 then
          begin
            while PeekMessage(Msg,PM_REMOVE) do
              begin
                TranslateMessage(Msg);
                DispatchMessage(Msg);
              end;
          end;
      end;
  finally
    DeallocateHWnd(fWndHandle);
  end;
end;

procedure TWndThread.WndProc(var Msg: TMessage);
begin
  case Msg.Msg of
    WM_MY_ACTION:
      begin
        inc(Test);
      end;
    else Msg.Result := DefWindowProc(fWndHandle,Msg.Msg,Msg.WParam,Msg.LParam);
  end;
end;

procedure TWndThread.DoAction;
begin
  PostMessage(fWndHandle,WM_MY_ACTION,0);
end;

var
  t: TWndThread;
begin
  t := TWndThread.Create;
  t.DoAction;
  t.Terminate;
end;

如果没有等待IsRunning标志的循环,DoAction将无法成功将消息发布到包含的窗口句柄,因为它尚未创建.基本上,WndProc中的inc(Test)不会被触发.

有没有更好的方法等待线程启动并在Execute方法中完成必要的初始化,或者这个解决方案是否得到了好处?

注意:我知道AllocateHWnd和DeallocateHWnd不是线程安全的,不应该像上面的例子那样在生产代码中使用.

解决方法

将FIsRunning从布尔值更改为TEvent,以便在所有内容都可以使用时发出信号.

现在您可以随时等待此事件(特别是在DoAction等公共方法中):

const
  WM_MY_ACTION = WM_APP + 10;

type
  TWndThread = class(TThread)
  private
    FIsRunning: TEvent; // <- event
  protected
    fWndHandle: THandle;
    procedure WndProc(var Msg: TMessage);
    procedure Execute; override;

    procedure CheckIsRunning; // guard method
  public
    constructor Create;
    destructor Destroy; override;
    procedure DoAction;
  end;

constructor TWndThread.Create;
begin
  // create event
  FIsRunning := TEvent.Create( nil,True,'' );
  inherited;
end;

destructor Destroy;
begin
  inherited;
  // free event
  FIsRunning.Free;
end;

procedure CheckIsRunning;
begin
  // guard if terminated
  if Terminated then
    raise Exception.Create( 'Already terminated' );
  // wait for event
  FIsRunning.WaitFor();
end;

procedure TWndThread.Execute;
var
  Msg: TMsg;
begin
  fWndHandle := AllocateHWnd(WndProc);

  // set event
  FIsRunning.SetEvent;

  try
    while not Terminated do
      begin
        if MsgWaitForMultipleObjects(0,Msg.LParam);
  end;
end;

procedure TWndThread.DoAction;
begin
  // guard method
  CheckIsRunning;
  // do the action
  PostMessage(fWndHandle,0);
end;

现在一切都很容易使用,你只需等待,如果有特殊原因等待(访问DoAction方法太快)

var
  t: TWndThread;
begin
  t := TWndThread.Create;
  try
    t.DoAction;
  finally
    t.Free;
  end;
end;

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读