使用Delphi,TIdSchedulerOfThreadPool初始化从Indy 9迁移到10
我正在将一个Delphi应用程序从Indy 9更新到Indy 10.
这很痛苦,显然已经发生了很多变化. 我陷入了困境. 这是旧代码(与Indy 9一起工作): 创建一个线程池,初始化然后启动池的每个线程. TUrlThread = class(TIdThread) ... var i: Integer; begin // create the Pool and init it Pool := TIdThreadMgrPool.Create(nil); Pool.PoolSize := Options.RunningThreads; Pool.ThreadClass:= TUrlThread; // init threads and start them for i := 1 to Options.RunningThreads do begin with (Pool.GetThread as TUrlThread) do begin Index := i; Controler := Self; Priority := Options.Priority; Start; end; end; Indy 10推出了TIdThreadMgrPool类. 我找了一个替代品,TIdSchedulerOfThreadPool看起来像一个胜利者, 这是修改后的(Indy 10)代码: TUrlThread = class(TIdThreadWithTask) ... var i: Integer; begin // create the Pool and init it Pool := TIdSchedulerOfThreadPool.Create(nil); Pool.PoolSize := Options.RunningThreads; Pool.ThreadClass:= TUrlThread; // init threads and start them for i := 1 to Options.RunningThreads do begin with (Pool.NewThread as TUrlThread) do begin Index := i; Controler := Self; Priority := Options.Priority; Start; end; end; 我在这里得到一个访问冲突异常(这是indy代码): procedure TIdTask.DoBeforeRun; begin FBeforeRunDone := True; BeforeRun; end; FBeforeRunDone是零. 解决方法
你是对的,TIdSchedulerOfThreadPool是Indy 10替代TIdThreadMgrPool的.但是,您没有考虑的是TIdScheduler架构与TIdThreadMgr架构有很大不同.
在Indy 10中,TIdThreadWithTask本身不能运行.顾名思义,TIdThreadWithTask执行一个Task,它是一个TIdTask派生的对象(例如TIdContext,它是Indy 10替代TIdPeerThread),它与该线程相关联.您正在运行线程而不给它们执行任务,这就是您遇到崩溃的原因.为了手动调用Start(),您需要首先创建一个基于TIdTask的对象并将其分配给TIdThreadWithTask.Task属性. TIdTCPServer通过调用TIdScheduler.AcquireYarn()来创建一个链接到TIdThreadWithTask对象的TIdYarn对象来处理它,然后创建一个TIdContext对象并将其传递给TIdScheduler.StartYarn(),它使用TIdYarn访问TIdThreadWithTask以分配其任务在之前调用Start()之前的属性. 但是,一切都不会丢失.在Indy 9和10中,你真的不应该手动调用TIdThread.Start()来开始. TIdTCPServer在接受新的客户端连接,从其ThreadMgr / Scheduler获取线程以及将客户端连接与线程相关联后为您处理.您可以根据需要初始化线程属性,而无需立即实际运行线程.这些属性将在线程第一次开始运行时生效. 试试这个: TUrlThread = class(TIdThread) ... var i: Integer; begin // create the Pool and init it Pool := TIdThreadMgrPool.Create(nil); Pool.PoolSize := Options.RunningThreads; Pool.ThreadClass:= TUrlThread; Pool.ThreadPriority := Options.Priority; // init threads and start them for i := 1 to Options.RunningThreads do begin with (Pool.GetThread as TUrlThread) do begin Index := i; Controler := Self; end; end; . TUrlThread = class(TIdThreadWithTask) ... var i: Integer; begin // create the Pool and init it Pool := TIdSchedulerOfThreadPool.Create(nil); Pool.PoolSize := Options.RunningThreads; Pool.ThreadClass:= TUrlThread; Pool.ThreadPriority := Options.Priority; // init threads and start them for i := 1 to Options.RunningThreads do begin with (Pool.NewThread as TUrlThread) do begin Index := i; Controler := Self; end; end; 现在,说到这一点,最后要注意的是.在Indy 9和10中,完成后线程可能不会被放回池中,并且在初始化代码运行后将新线程添加到池中. PoolSize是池中保留的最小线程数,而不是绝对计数.不仅PoolSize数量的客户端可以连接到服务器,它将在需要时为它们创建更多线程,从而绕过初始化代码.在这两个版本中,初始化线程的最佳位置是TUrlThread构造函数.将Controler指针存储在构造函数可以在需要时到达的位置.由于池中线程的顺序随时间动态变化,因此为每个线程分配索引没有意义. 实际上,由于其他原因,您的手动初始化代码在两个版本中实际上都是错误的approch. TIdThreadMgrPool.GetThread()和TIdSchedulerOfThreadPool.NewThread()都不会将新线程添加到池中.当线程停止运行时,线程将被添加到Indy 9和10中的池中,并且有空间可以保存线程以供重用,而且只有在TIdTCPServer启动时才在Indy 10中.因此,您实际上创建的线程实际上并没有执行任何操作,也没有被池跟踪.更有理由在两个版本中重新设计初始化代码,以便线程在正常条件下创建时初始化自己,而不是入侵体系结构以手动创建它们. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |