Multithreading 线程如何通知没有';你没有窗户把手吗?
我是多线程新手,但不是一个完全的新手。我需要在工作线程中执行对webservice的调用 在主线程中,我有一个带有私有数据成员(私有字符串)的表单(TForm),只有工作线程会向其写入数据(在线程恢复之前,我将指向它的指针传递到线程中)。当工作线程完成其webservice调用并将结果响应xml写入表单上的私有成员时,工作线程使用PostMessage将消息发送到表单的句柄(在它恢复之前,我也将该消息传递到线程) 它工作得很好,但是现在我想从一个数据模块(没有句柄)做同样的事情。。。因此,我非常希望能有一些有用的代码来补充我的工作模型 编辑 我真正想要的是代码(如果可能的话),它允许我替换行Multithreading 线程如何通知没有';你没有窗户把手吗?,multithreading,delphi,windows-messages,Multithreading,Delphi,Windows Messages,我是多线程新手,但不是一个完全的新手。我需要在工作线程中执行对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也会自动激发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;