Cas*_*ady 5 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;
Run Code Online (Sandbox Code Playgroud)
该TIdThreadMgrPool类旷古印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;
Run Code Online (Sandbox Code Playgroud)
我在这里得到一个访问冲突异常(这是indy代码):
procedure TIdTask.DoBeforeRun;
begin
FBeforeRunDone := True;
BeforeRun;
end;
Run Code Online (Sandbox Code Playgroud)
FBeforeRunDone是零.
你是正确的,TIdSchedulerOfThreadPool
是Indy 10的替代品TIdThreadMgrPool
.但是,您没有考虑的是该TIdScheduler
体系结构与体系结构有很大不同TIdThreadMgr
.
在Indy 10中,TIdThreadWithTask
不能单独操作.顾名思义,TIdThreadWithTask
执行一个Task,它是一个与线程相关联的TIdTask
衍生对象(例如TIdContext
,Indy 10的替代品TIdPeerThread
).您正在运行线程而不给它们执行任务,这就是您遇到崩溃的原因.要Start()
手动调用,您需要首先创建并TIdTask
为TIdThreadWithTask.Task
属性分配基于对象的对象. TIdTCPServer
通过调用TIdScheduler.AcquireYarn()
创建一个TIdYarn
链接到TIdThreadWithTask
对象的对象来处理它,然后创建一个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;
Run Code Online (Sandbox Code Playgroud)
.
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;
Run Code Online (Sandbox Code Playgroud)
现在,说到这一点,最后要注意的是.在Indy 9和10中,完成后线程可能不会被放回池中,并且在初始化代码运行后将新线程添加到池中.这PoolSize
是池中保留的最小线程数,而不是绝对计数.超过PoolSize
多个客户端可以连接到服务器,它将很乐意在需要时为它们创建更多线程,从而绕过您的初始化代码.在这两个版本中,初始化线程的最佳位置是TUrlThread
构造函数.将Controler
指针存储在构造函数可以在需要时到达的位置.Index
由于池中线程的顺序随时间动态变化,因此为每个线程分配一个没有意义.
实际上,由于其他原因,您的手动初始化代码在两个版本中实际上都是错误的approch.双方TIdThreadMgrPool.GetThread()
并TIdSchedulerOfThreadPool.NewThread()
没有新的线程添加到池中的.当线程停止运行时,线程被添加到Indy 9和10中的池中,并且有空间来保存线程以供重用,另外在Indy 10中仅在TIdTCPServer
启动时.因此,您实际上创建的线程实际上并没有执行任何操作,也没有被池跟踪.更有理由在两个版本中重新设计初始化代码,以便线程在正常条件下创建时初始化自己,而不是入侵体系结构以手动创建它们.