我正在更新一个从Indy 9到Indy 10的Delphi应用程序。
这是相当痛苦的,因为显然有很多变化。
我被困在一步。
下面是旧代码(使用Indy 9):
创建线程池,并初始化池中的每个线程,然后启动。单独的线程创建一个indy客户端(但这里并不重要)。
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是零。
发布于 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获得一个线程并将客户机连接与该线程相关联之后,为您处理这个问题。您可以根据需要初始化线程属性,而不必立即实际运行线程。这些属性将在线程以后第一次开始运行时生效。
试试这个:
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指针存储在构造函数可以在需要时到达的地方。为每个线程分配一个Index是没有意义的,因为池中线程的顺序会随着时间的推移而动态变化。
实际上,由于另一个原因,手动初始化代码在这两个版本中实际上都是错误的。TIdThreadMgrPool.GetThread()和TIdSchedulerOfThreadPool.NewThread()都没有向池中添加新线程。当线程停止运行并且有空间保存线程以供重用时,线程将在Indy 9和10中添加到池中,另外,只有在启动TIdTCPServer时,才会在Indy 10中添加线程。因此,您实际上创建的线程实际上没有执行任何操作,也没有被池跟踪。更有理由在这两个版本中重新设计您的初始化代码,这样线程在正常情况下创建时就会初始化自己,而不是您侵入体系结构来手动创建它们。
https://stackoverflow.com/questions/14514810
复制相似问题