gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 15:09:17 29 4
gpt4 key购买 nike

我正在将 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 为零。

最佳答案

您认为 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 code> 分配其 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 中,当线程停止运行并且有空间保存线程以供重用时,线程才会添加到池中,此外,在 Indy 10 中,仅当 TIdTCPServer 启动时才将线程添加到池中。因此,您实际上创建的线程实际上没有执行任何操作,也没有被池跟踪。更有理由在这两个版本中重新设计初始化代码,以便线程在正常情况下创建时自行初始化,而不是侵入体系结构手动创建它们。

关于delphi - 使用 Delphi 从 Indy 9 迁移到 10,TIdSchedulerOfThreadPool 初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14514810/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com