Multithreading 在TidHTTPServer.OnCommandGet内创建对象(使用计时器)失败
在Multithreading 在TidHTTPServer.OnCommandGet内创建对象(使用计时器)失败,multithreading,delphi,indy10,delphi-10.3-rio,Multithreading,Delphi,Indy10,Delphi 10.3 Rio,在TidHTTPServer.OnCommandGet中,我创建了一个新对象。此对象有一个计时器,该计时器应立即启动,但不启动。时光之翼从不开火! 当我在其他地方创建对象时,它会工作 一些代码 TVolumeFader=Class(TObject) ... constructor TVolumeFader.Create(...); begin inherited Create; ... VolTimer:=TTimer.Create(NIL); VolTime
TidHTTPServer.OnCommandGet中,我创建了一个新对象。此对象有一个计时器,该计时器应立即启动,但不启动。时光之翼从不开火!
当我在其他地方创建对象时,它会工作
一些代码
TVolumeFader=Class(TObject)
...
constructor TVolumeFader.Create(...);
begin
inherited Create;
...
VolTimer:=TTimer.Create(NIL);
VolTimer.Enabled:=FALSE;
VolTimer.Interval:=100;
VolTimer.OnTimer:=DoTimerTick;
end;
procedure TVolumeFader.DoTimerTick(Sender:TObject);
begin
LogWrite('TimerTick in VolumeFader',Debug);
If Assigned(VolTimer)then Begin;
VolTimer.Enabled:=FALSE;
End;
try
LogWrite('Executing VolumeFade in VolumeFader',Debug);
VolumeFade;
finally
If Assigned(VolTimer)then
VolTimer.Enabled:=TRUE;
end;
end;
procedure TMain.OnCommandGet;
Begin;
TVolumeFader.Create(...);
End;
在对象的构造函数中,您正在创建TTimer
ok,但正在将其Enabled
属性设置为False
。因此,请确保在构造函数退出后实际激活计时器。或者在构造函数中将False
更改为True
话虽如此,您的代码仍然无法如图所示工作。这是因为TIdHTTPServer
是一个多线程组件,它的OnCommand…
事件在TIdHTTPServer
客户端连接到服务器时为自身创建的工作线程上下文中激发。但是TTimer
是一个基于消息的计时器,它为自己创建一个内部HWND
,该线程绑定到创建它的线程,并且该线程必须有一个消息循环,以便TTimer
处理WM_timer
消息。在中创建TTimer
的工作线程没有消息循环,因此TTimer
将无法触发其OnTimer
事件
因此,您必须:
创建对象后,在OnCommand…
事件处理程序中运行自己的消息循环,然后在事件处理程序退出之前释放该对象。无法保证调用线程在OnCommand…
事件处理程序退出后将继续运行。请注意,当计时器运行时,客户端将被阻止向服务器发送任何进一步的HTTP命令:
过程TMain.OnCommandGet(AContext:TIdContext;
ARequestInfo:TIdHTTPRequestInfo;AResponseInfo:TIdHTTPResponseInfo);
变量
音量控制器:TVolumeFader;
msg:tagMSG;
开始
...
音量控制器:=TVolumeFader.Create(…);
尝试
当(计时器应保持运行)运行时
开始
//Application.ProcessMessages;
如果peek消息(@msg,0,0,PM_REMOVE)那么
开始
翻译信息(@msg);
发送消息(@msg);
结束其他
睡眠(100);
结束;
最后
音量控制器。免费;
结束;
...
结束;
将对象的创建及其TTimer
委托给主UI线程,以便在该线程的上下文中而不是在服务器的工作线程的上下文中触发OnTimer
事件处理程序。只要确保您的OnTimer
代码是线程安全的,如果它需要访问与服务器共享的任何内容:
过程TMain.OnCommandGet(AContext:TIdContext;
ARequestInfo:TIdHTTPRequestInfo;AResponseInfo:TIdHTTPResponseInfo);
开始
...
TThread.Synchronize(nil、//或TThread.Queue()
程序
开始
TVolumeFader.Create(…);//何时销毁此对象?
结束
);
...
结束;
它不起作用,因为您创建了它,然后立即将其设置为启用:=False
。如果您阅读代码,则会有所帮助。:-)禁用计时器时,OnTimer
事件不会发生。使用调试器一步一步地检查代码,您可以很容易地发现这些问题。您发布的代码中也有拼写错误,这说明您没有复制/粘贴自己的代码。请不要在您的帖子中重新键入代码,因为它很容易引入新的错误,可能会产生误导,或导致发布错误的答案。@KenWhite即使启用了计时器,它仍然无法如图所示工作,因为创建计时器的线程没有消息loop@RemyLebeau当前位置我错过了一个与印第岛有关的问题。但是它不能在上面用户发布的代码中工作的主要原因是它从未被启用。谢谢你的建议。同步工作完美@<代码>已启用:很抱歉缺少代码段,已启用
在所有回调事件设置完毕后立即设置为“true”@<代码>销毁:对象在完成其作业后销毁自身。