想知道是否有人可以提供一个非常棘手的零星(不一致可重复)问题 - 可能与线程有关。我在Delphi 7(它的旧代码......)中运行了一个IdHttpListener(Indy)。下面的代码是从一个大型繁琐的应用程序复制 - 但希望足以解释。传入的HTTP请求运行以下事件 - 其中web_lock是我在顶部定义的TCriticalSection。我在一个关键部分做这件事,因为Web请求会导致我需要变化的变化。
procedure TFWebServer.WebServerCommandGet(Thread: TIdPeerThread;
RequestInfo: TIdHTTPRequestInfo; ResponseInfo: TIdHTTPResponseInfo);
var S,PageString : string;
begin
web_lock.Acquire;
PageString:=' ';
if (copy(RequestInfo.Document,1,15)='/_Request_Part_') then begin
s:=copy(RequestInfo.Document,16,length(RequestInfo.Document));
FMainGui.doFunction(s);
PageString:='OK';
end; // Lots more else cases here...
ResponseInfo.ContentType:='text/plain';
ResponseInfo.ResponseNo:=200;
ResponseInfo.ContentStream:=TMemoryStream.Create;
ResponseInfo.ContentStream.Write(PageString[1],length(PageString)*
sizeof(PageString[1]));
ResponseInfo.ContentLength:=length(PageString)*sizeof(PageString[1]);
web_lock.Release;
end;
然后,我的FMainGui.doFunction做了类似的事情: -
procedure doFunction(s : String);
var i,j : integer;
begin
i:=strtoint(s);
for j:=1 to Pages do begin // Pages is dynamic - but correctly set
if (j=i) then // Pagelabs[j] is always a visible TLabel
Pagelabs[j].Font.Style:=[fsBold]
else Pagelabs[j].Font.Style:=[];
end;
end;
位简化 - Pagelabs是我在页面上显示的一组动态创建的TLabel,您使用Web请求选择的TLabel变为粗体。
问题:有时候,不可预测的是,我遇到了处理网页请求的某种僵局 - 它只是用圆形的旋转鼠标指针冻结,并且无法恢复。如果我在Delphi中调试它,那么调用堆栈是空的,我只能单步执行汇编代码 - 我担心我不能正常工作!我通过在每一行代码之间写一行文本文件来跟踪上面的Pagelabs [j] .Font.Style:= [fsBold]行...所以虽然错误是零星的,当它确实发生时,它总是被它锁定的那条线。
我很欣赏这是一个大型应用程序的片段,但是有什么明显的我做错了吗?例如 - 从HTTP侦听器触发的线程更改GUI属性是否安全?或者我应该做些什么?
任何想法都非常感激, 谢谢, 韦斯
答案 0 :(得分:4)
您无法仅从主GUI线程操纵工作线程的UI控件!
您有两种选择:
您可以通过TThread.Synchronize()
过程阻止HTTP线程并临时切换到主线程。就像在这个例子中一样:
http://docwiki.embarcadero.com/CodeExamples/Seattle/en/Synchronize_(Delphi)
您可能更喜欢通过
延迟不同步执行Windows消息(使用PostMessage并避免SendMessage)http://www.cryer.co.uk/brian/delphi/howto_send_custom_window_message.htm
AsyncCall库http://andy.jgknet.de/blog/bugfix-units/asynccalls-29-asynchronous-function-calls/
使用类似OmniThreadsLibrary的线程队列方法
第一个选项可能会降低你的速度,因为GUI线程中的任何长处理都会冻结你的HTTP处理程序。
第二个选项需要制作一个"快照"复制任何所需数据并将其与延迟调用请求一起传递(因为VCL更新代码可能在HTTP处理程序(或几个HTTP处理程序)之后的任何随机时间执行。当多个HTTP处理程序时,这是正常的)会请求GUI更新,你必须检查哪些传递了最新的数据,并跳过其他请求,例如。