Multithreading 如何在多个WNDPOC之间序列化消息?
我在主线程中创建了两个WndProc,然后几乎同时从其他线程向每个线程发布消息,但从WndProc1开始。这个WNDPOC1有一个任务要做,它会持续一段时间。。。它在开始和结束时都会发出信号。WNDPOC2在被访问时也会发出信号。现在,当我按下按钮开始这个测试时,我得到:“P1进入…[延迟]…P1离开WndProc2”。如您所见,第二条消息等待WNDPOC1完成,尽管他被发送到WNDPOC2!我想知道的是,如果这两个WNDPOC没有任何共同点,这个序列化是如何工作的?我认为,即使我有两个不同的组件,每个组件都有自己的WndProc(但我没有检查)Multithreading 如何在多个WNDPOC之间序列化消息?,multithreading,delphi,message,Multithreading,Delphi,Message,我在主线程中创建了两个WndProc,然后几乎同时从其他线程向每个线程发布消息,但从WndProc1开始。这个WNDPOC1有一个任务要做,它会持续一段时间。。。它在开始和结束时都会发出信号。WNDPOC2在被访问时也会发出信号。现在,当我按下按钮开始这个测试时,我得到:“P1进入…[延迟]…P1离开WndProc2”。如您所见,第二条消息等待WNDPOC1完成,尽管他被发送到WNDPOC2!我想知道的是,如果这两个WNDPOC没有任何共同点,这个序列化是如何工作的?我认为,即使我有两个不同的组
你所看到的完全是意料之中的。每个线程只有一个消息队列,并且可能有零到多个窗口句柄。窗口句柄通常对应于可视组件,但不一定像示例中那样 在代码中的某个地方(对于Delphi中的GUI,这是在Forms单元中),有一个所谓的“消息循环”,它从队列中检索消息并将它们发送到相应的
WndProc
。分派机制类似于一个简单的函数调用:它在处理消息时阻塞,除非消息处理程序再次调用消息泵(如果处理不正确,问题就会出现)。查看并查看表单单元中的TApplication.ProcessMessages
,以及类单元中的AllocateHWnd
/DeallocateHWnd
如果要并行执行代码,必须创建单独的线程;只要线程少于CPU内核,并且线程没有被I/O或互斥锁、信号量和关键部分阻塞,每个线程都将并行执行。如果准备执行的线程太多,则使用抢占式多任务调度
您可以使用消息在线程之间进行通信。为此,线程必须创建窗口句柄并具有消息泵
在Delphi中,GUI只能从主线程访问。如果次线程有要显示的内容,那么它必须让主线程执行显示代码,很可能再次通过次线程/工作线程和主线程之间的消息执行,或者使用
同步方法,或者使用其他通信机制,例如管道、套接字、文件I/O、共享内存。单独或组合。事实上,消息是从消息队列中逐个检索的。在处理您先前发布的邮件之前,不会检索和处理您稍后发布的邮件。正如您所看到的,不同的窗口过程或不同的组件,它们的共同点是消息队列-它们生活在同一个线程中,因此共享同一个队列。但这是我不理解的。。。两个(或更多)窗口过程如何具有相同的mesage队列?消息队列是线程的特性,而不是窗口。请参阅。不确定这是否明显,您创建了不同的线程,但这些不同的线程正在发布到同一个(main/gui)线程(因为它们发布到的窗口是由主线程创建的)。我不希望代码并行执行,事实上,这正是我想要避免的。:)我想确保将消息发布到同一线程的多个窗口是线程安全的。谢谢你的解释!如果您允许我再问一个问题,当我使用AllocateHwnd
创建新窗口时,我如何知道为哪个线程创建了线程?请打开一个新问题,而不是在评论中询问。AllocateHwnd在调用线程的上下文中工作。
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, SyncObjs;
type
TMyThread = class(TThread)
private
FHnd: HWND;
FTime: Integer;
protected
procedure Execute; override;
public
constructor Create(AHnd: HWND; ATime: Integer);
end;
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
TestHand1, TestHand2: HWND;
MyT1, MyT2: TMyThread;
protected
procedure TestWndProc1(var Msg: TMessage);
procedure TestWndProc2(var Msg: TMessage);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
constructor TMyThread.Create(AHnd: HWND; ATime: Integer);
begin
inherited Create;
FHnd:= AHnd;
FTime:= ATime;
end;
procedure TMyThread.Execute;
begin
Sleep(FTime);
PostMessage(FHnd, WM_USER, 0, 0);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
TestHand1:= AllocateHWnd(TestWndProc1);
TestHand2:= AllocateHWnd(TestWndProc2);
end;
procedure TForm1.TestWndProc1(var Msg: TMessage);
var I: Integer;
A, B, C: Cardinal;
begin
if Msg.Msg = WM_USER then begin
Caption:= Caption + ' P1-Enter';
A:= $12345678; B:= $98765432;
for I:= 1 to 180000000 do begin
C:= A * B; B:= C * A; A:= B * C;
end;
Caption:= Caption + ' P1-Leave';
end;
end;
procedure TForm1.TestWndProc2(var Msg: TMessage);
begin
if Msg.Msg = WM_USER then
Caption:= Caption + ' WndProc2';
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Caption:= '';
MyT1:= TMyThread.Create(TestHand1, 300);
MyT2:= TMyThread.Create(TestHand2, 350);
end;
end.