使用Delphi,TIdSchedulerOfThreadPool初始化从Indy 9迁移到10

时间:2013-01-25 03:20:59

标签: delphi indy indy10 indy-9

我正在将一个Delphi应用程序从Indy 9更新到Indy 10。

这很痛苦,显然有很多变化。

我被困在一步。

这是旧代码(与Indy 9合作):

创建一个线程池,初始化然后启动池的每个线程。 各个线程创建一个indy http客户端(但这里没关系)。

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;

TIdThreadMgrPool 类与Indy 10一起消失了。

我找了一个替代品, 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是零。

1 个答案:

答案 0 :(得分:7)

TIdSchedulerOfThreadPool是Indy 10代替TIdThreadMgrPool的,这是正确的。但是,您没有考虑到的是TIdScheduler架构与TIdThreadMgr架构有很大不同。

在Indy 10中,TIdThreadWithTask本身并不运作。顾名思义,TIdThreadWithTask执行任务,这是TIdTask派生的对象(例如TIdContext,它是Indy 10的替代{{1} }}与线程相关联。您正在运行线程而不给它们执行任务,这就是您遇到崩溃的原因。要手动调用TIdPeerThread,您需要先创建基于Start()的对象并将其分配给TIdTask属性。 TIdThreadWithTask.Task通过调用TIdTCPServer来创建链接到TIdScheduler.AcquireYarn()对象的TIdYarn对象来处理它,然后创建一个TIdThreadWithTask对象并将其传递给{{ 1}},使用TIdContext访问TIdScheduler.StartYarn()以分配其TIdYarn属性,然后再调用TIdThreadWithTask

然而,一切都不会丢失。在Indy 9和10中,你真的不应该手动调用Task来开始。 Start()在接受新的客户端连接,从TIdThread.Start() / TIdTCPServer获取线程,并将客户端连接与线程关联后,为您处理。您可以根据需要初始化线程属性,而无需立即实际运行线程。这些属性将在线程第一次开始运行时生效。

试试这个:

ThreadMgr

Scheduler

现在,说到这一点,最后要注意的是。在Indy 9和10中,完成后线程可能不会被放回池中,并且在初始化代码运行后将新线程添加到池中。 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; 个客户端可以连接到服务器,并且可以在需要时为它们创建更多线程,从而绕过初始化代码。在这两个版本中,初始化线程的最佳位置是PoolSize构造函数。将PoolSize指针存储在构造函数可以在需要时到达的位置。由于池中线程的顺序随时间动态变化,因此为每个线程分配TUrlThread没有意义。

事实上,由于其他原因,您的手动初始化代码在两个版本中实际上都是错误的approch。 ControlerIndex都不会将新线程添加到池中。当线程停止运行并且有空间保存线程以供重用时,线程将被添加到Indy 9和10中的池中,并且仅在{0}启动时才在Indy 10中。因此,您实际上创建的线程实际上并没有执行任何操作,也没有被池跟踪。更有理由在两个版本中重新设计初始化代码,以便线程在正常条件下创建时初始化自己,而不是侵入体系结构以手动创建它们。