首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Delphi从Indy 9迁移到10,TIdSchedulerOfThreadPool初始化

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

Stack Overflow用户
提问于 2013-01-25 03:20:58
回答 1查看 2.7K关注 0票数 5

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

这是相当痛苦的,因为显然有很多变化。

我被困在一步。

下面是旧代码(使用Indy 9):

创建线程池,并初始化池中的每个线程,然后启动。单独的线程创建一个indy客户端(但这里并不重要)。

代码语言:javascript
复制
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)代码:

代码语言:javascript
复制
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代码):

代码语言:javascript
复制
procedure TIdTask.DoBeforeRun;
begin
  FBeforeRunDone := True;
  BeforeRun;
end;

FBeforeRunDone是零。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-01-25 09:42:39

你是正确的,TIdSchedulerOfThreadPool是印第10代TIdThreadMgrPool的替代品。但是,您没有考虑到的是,TIdScheduler体系结构与TIdThreadMgr体系结构有很大的不同。

在Indy 10中,TIdThreadWithTask并不是自己操作的。顾名思义,TIdThreadWithTask执行一个任务,它是一个与线程关联的TIdTask-derived对象(比如TIdContext,它是Indy 10对TIdPeerThread的替代)。您正在运行线程,而不让它们执行任务,这就是您正经历崩溃的原因。为了手动调用Start(),您需要首先创建一个TIdTask-based对象并将其分配给TIdThreadWithTask.Task属性。TIdTCPServer通过调用TIdScheduler.AcquireYarn()创建一个链接到TIdThreadWithTask对象的TIdYarn对象来处理这个问题,然后创建一个TIdContext对象并将其传递给TIdScheduler.StartYarn(),后者使用TIdYarn访问TIdThreadWithTask来分配其Task属性,然后调用Start()

然而,并不是所有的东西都丢失了。在Indy 9和10中,首先不应该手动调用TIdThread.Start()TIdTCPServer在接受一个新的客户端连接、从它的ThreadMgr/Scheduler获得一个线程并将客户机连接与该线程相关联之后,为您处理这个问题。您可以根据需要初始化线程属性,而不必立即实际运行线程。这些属性将在线程以后第一次开始运行时生效。

试试这个:

代码语言:javascript
复制
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;

代码语言:javascript
复制
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指针存储在构造函数可以在需要时到达的地方。为每个线程分配一个Index是没有意义的,因为池中线程的顺序会随着时间的推移而动态变化。

实际上,由于另一个原因,手动初始化代码在这两个版本中实际上都是错误的。TIdThreadMgrPool.GetThread()TIdSchedulerOfThreadPool.NewThread()都没有向池中添加新线程。当线程停止运行并且有空间保存线程以供重用时,线程将在Indy 9和10中添加到池中,另外,只有在启动TIdTCPServer时,才会在Indy 10中添加线程。因此,您实际上创建的线程实际上没有执行任何操作,也没有被池跟踪。更有理由在这两个版本中重新设计您的初始化代码,这样线程在正常情况下创建时就会初始化自己,而不是您侵入体系结构来手动创建它们。

票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14514810

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档