VCL不支持多线程,因此我认为在INDY 10 TCP server.execute(...)
函数中写入GUI信息不是一个好主意。
如何从server execute发送信息到VCL?
我需要在tcpserver.execute
函数内修改TBitmap。如何做到线程安全?
TThread.Synchronize
和 TThread.Queue
。TBitmap
不需要与主线程同步。只要您在一次只有一个线程中修改它,就可以从任何想要的线程中进行修改。您可以使用标准的同步对象(如关键部分和事件),以确保只有一个线程同时使用它。最佳同步方式是创建并使用TidNotify的派生类。
定义一个TidNotify的派生类和VCL过程,包括相应的私有字段。
TVclProc= procedure(aBMP: TBitmap) of object;
TBmpNotify = class(TIdNotify)
protected
FBMP: TBitmap;
FProc: TVclProc;
procedure DoNotify; override;
public
constructor Create(aBMP: TBitmap; aProc: TVclProc); reintroduce;
class procedure NewBMP(aBMP: TBitmap; aProc: TVclProc);
end;
{ TBmpNotify }
constructor TBmpNotify.Create(aBMP: TBitmap; aProc: TVclProc);
begin
inherited Create;
FBMP:= aBMP;
FProc:= aProc;
end;
procedure TBmpNotify.DoNotify;
begin
inherited;
FProc(FBMP);
end;
class procedure TBmpNotify.NewBMP(aBMP: TBitmap; aProc: TVclProc);
begin
with Create(aBMP, aProc) do
begin
Notify;
end;
end;
server.execute(...)
procedure TTCPServer.DoExecute(aContext: TIdContext);
var
NewBMP: TBitmap;
begin
TBmpNotify.NewBMP(NewBMP, FVclBmpProc);
end;
FVclBmpProc是一个指向与TVclProc参数签名相匹配的表单上过程的私有字段。该字段应通过服务器对象上的属性在创建后并在启动服务器之前进行设置。
表单上的方法将可以自由使用接收到的位图,而不用担心线程争用、死锁和其他访问VCL控件时出现的问题,因为它们没有同步。
只需要一个简单的PostMessage(在线程内部)和处理消息(在线程外部),就可以进行UI更新...
TIdNotify.NotifyMethod
是异步运行的,因为它仅仅调用了TThread.Queue
。难道你尝试做的事情中有 20% 需要同步访问 VCL 吗? - Rob Kennedy