Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 线程如何通知没有';你没有窗户把手吗?_Multithreading_Delphi_Windows Messages - Fatal编程技术网

Multithreading 线程如何通知没有';你没有窗户把手吗?

Multithreading 线程如何通知没有';你没有窗户把手吗?,multithreading,delphi,windows-messages,Multithreading,Delphi,Windows Messages,我是多线程新手,但不是一个完全的新手。我需要在工作线程中执行对webservice的调用 在主线程中,我有一个带有私有数据成员(私有字符串)的表单(TForm),只有工作线程会向其写入数据(在线程恢复之前,我将指向它的指针传递到线程中)。当工作线程完成其webservice调用并将结果响应xml写入表单上的私有成员时,工作线程使用PostMessage将消息发送到表单的句柄(在它恢复之前,我也将该消息传递到线程) 它工作得很好,但是现在我想从一个数据模块(没有句柄)做同样的事情。。。因此,我非常

我是多线程新手,但不是一个完全的新手。我需要在工作线程中执行对webservice的调用

在主线程中,我有一个带有私有数据成员(私有字符串)的表单(TForm),只有工作线程会向其写入数据(在线程恢复之前,我将指向它的指针传递到线程中)。当工作线程完成其webservice调用并将结果响应xml写入表单上的私有成员时,工作线程使用PostMessage将消息发送到表单的句柄(在它恢复之前,我也将该消息传递到线程)

它工作得很好,但是现在我想从一个数据模块(没有句柄)做同样的事情。。。因此,我非常希望能有一些有用的代码来补充我的工作模型

编辑

我真正想要的是代码(如果可能的话),它允许我替换行

MyWorkerThread.SenderHandle := self.Handle;


我以前曾成功地使用过这种技术:


基本上,在通过AllocateHWND获得的句柄上使用第二个线程作为消息泵。这的确令人恼火,你最好使用一个库来处理所有的细节。我更喜欢,但是还有其他的-请参阅和。

您可以使用AllocateHwnd分配您自己的句柄,并将其用作PostMessage目标

TTestThread = class(TThread)
private
  FSignalShutdown: boolean;
  // hidden window handle 
  FWinHandle: HWND;                       
protected
  procedure Execute; override;
  // our window procedure 
  procedure WndProc(var msg: TMessage);   
public
  constructor Create;
  destructor Destroy; override;
  procedure PrintMsg;
end;

constructor TTestThread.Create;
begin
  FSignalShutdown := False;

  // create the hidden window, store it's 
  // handle and change the default window 
  // procedure provided by Windows with our 
  // window procedure 

  FWinHandle := AllocateHWND(WndProc);
  inherited Create(False);
end;

destructor TTestThread.Destroy;
begin
  // destroy the hidden window and free up memory 
  DeallocateHWnd(FWinHandle);
  inherited;
end;

procedure TTestThread.WndProc(var msg: TMessage);
begin
  if Msg.Msg = WM_SHUTDOWN_THREADS then
    // if the message id is WM_SHUTDOWN_THREADS
    // do our own processing        
    FSignalShutdown := True 
  else        
    // for all other messages call 
    // the default window procedure 
    Msg.Result := DefWindowProc(FWinHandle, Msg.Msg, 
                                Msg.wParam, Msg.lParam);
end;

您可以将其应用于任何对象,而不仅仅是线程。请注意,AllocateHWND并非如图所示的线程安全。

基于事件使用的备选方案:

  • 将线程(已存在)与标志结合使用:

    TMyDataModule = class(TDataModule)
    private    
      procedure OnWebServiceCallComplete(Sender: TObject);
    ...  
    
    TMyThread = class(TThread)
    public
      property TerminateFlag: Integer ...
    ...
    
    procedure TMyDataModule.StartWorkerThread;
      ...
      MyWorkerThread.OnTerminate := <Self.>OnWebServiceCallComplete;
      ...
    
    procedure TMyDataModule.OnWebServiceCallComplete(Sender: TObject);
    begin
      if MyWorkerThread.TerminateFlag = WEBCALL_COMPLETE then
        ...
    end;
    
    TMyDataModule=class(TDataModule)
    私有的
    WebServiceCallComplete上的过程(发送方:ToObject);
    ...  
    TMyThread=class(TThread)
    公众的
    属性TerminateFlag:整数。。。
    ...
    程序TMyDataModule.StartWorkerThread;
    ...
    MyWorkerThread.OnTerminate:=OnWebServiceCallComplete;
    ...
    过程TMyDataModule.OnWebServiceCallComplete(发送方:TObject);
    开始
    如果MyWorkerThread.TerminateFlag=WEBCALL\u完成,则
    ...
    结束;
    
    在执行例程中设置TerminateFlag。即使FreeOnTerminate为True,OnTerminate也会自动激发

  • 向thread类添加一个新的事件属性,您可以在其中提供标志作为参数来指示终止/线程结果。差不多。请确保同步事件调用。或者忘记参数,只在执行顺利完成时调用事件(就像您现在所做的那样)


  • AllocateHwnd不是线程安全的,这是一个非常令人恼火的原因。看来Embarcadero不会改变他们的政策。我使用我自己的noddy钩子代码在运行时用受关键部分保护的版本替换AllocateHwnd。@大卫:同意,但他们的代码中有一些更令人恼火的东西仍然没有得到修复:)如果它只是AllocateHwnd,我会很高兴的。只要新线程是由GUI线程创建的,这个代码没有问题。构造函数是在调用它的线程的上下文中运行的。我真的很欣赏这种选择。它看起来更优雅。我会试试的。再想一想,使用消息是我的首选模式。不管怎样,谢谢你。谢谢你没有重新发明轮子。查看OmniThreadLibrary.AllocateHWnd完成了这项工作。谢谢你,莫兹。
    TTestThread = class(TThread)
    private
      FSignalShutdown: boolean;
      // hidden window handle 
      FWinHandle: HWND;                       
    protected
      procedure Execute; override;
      // our window procedure 
      procedure WndProc(var msg: TMessage);   
    public
      constructor Create;
      destructor Destroy; override;
      procedure PrintMsg;
    end;
    
    constructor TTestThread.Create;
    begin
      FSignalShutdown := False;
    
      // create the hidden window, store it's 
      // handle and change the default window 
      // procedure provided by Windows with our 
      // window procedure 
    
      FWinHandle := AllocateHWND(WndProc);
      inherited Create(False);
    end;
    
    destructor TTestThread.Destroy;
    begin
      // destroy the hidden window and free up memory 
      DeallocateHWnd(FWinHandle);
      inherited;
    end;
    
    procedure TTestThread.WndProc(var msg: TMessage);
    begin
      if Msg.Msg = WM_SHUTDOWN_THREADS then
        // if the message id is WM_SHUTDOWN_THREADS
        // do our own processing        
        FSignalShutdown := True 
      else        
        // for all other messages call 
        // the default window procedure 
        Msg.Result := DefWindowProc(FWinHandle, Msg.Msg, 
                                    Msg.wParam, Msg.lParam);
    end;
    
    TMyDataModule = class(TDataModule)
    private    
      procedure OnWebServiceCallComplete(Sender: TObject);
    ...  
    
    TMyThread = class(TThread)
    public
      property TerminateFlag: Integer ...
    ...
    
    procedure TMyDataModule.StartWorkerThread;
      ...
      MyWorkerThread.OnTerminate := <Self.>OnWebServiceCallComplete;
      ...
    
    procedure TMyDataModule.OnWebServiceCallComplete(Sender: TObject);
    begin
      if MyWorkerThread.TerminateFlag = WEBCALL_COMPLETE then
        ...
    end;