【问题标题】:Delphi not all threads executing simultaneouslyDelphi 并非所有线程同时执行
【发布时间】:2014-07-21 09:59:23
【问题描述】:

我有以下场景:

我正在编写的程序模拟多个空中网络。现在我已经编写了它,以便每个模拟都在自己的线程中使用自己的数据。这样就不会污染数据,并且每个线程都是完整的多任务安全。我已经为每个线程实现了 delphi 的原生 TThread 类。

程序有一个主线程。然后它为每个网络创建多个子线程(我当前的测试用例有 6 个)。但是每个子线程也有 4 个额外的线程,因为它的网络有不止一个布局。所以我总共有 31 个线程,但只有 24 个线程在积极处理。所有线程都以挂起模式创建,以便我可以手动启动它们。

我正在运行的计算机是 i5 笔记本电脑,因此它有 4 个线程(2 个物理内核 + 2 个 HT)。在生产环境中,这将在服务器上运行,因此它们将拥有更多的处理能力。

现在在主程序线程中,我在执行线程的 for 循环之后添加了一个断点。这不会立即触发。观察 Delphi 的调试控制台,看起来它一次只主动运行 4 个线程。一旦一个退出,它就会启动另一个线程。

线程中的模拟很难优化,需要几个循环才能完成模拟。每个循环都需要前一个循环的数据。但每个模拟都完全独立于下一个模拟,因此该程序是螺纹和管道衬里的绝佳候选者。

现在我的问题是为什么它只启动 4 个线程而不是代码指定的所有线程?

编辑添加的代码片段

主程序

    for i := 0 to length(Solutions)-1 do
    begin
        Solutions[i].CreateWorkers;  //Setup threads 
    end;
    for i := 0 to length(Solutions)-1 do
    begin
        Solutions[i].Execute;   //start threads
    end;
end;

isSolversBusy := false;    //breaking point doesn't trigger here

第一级线程

procedure cSolution.Execute;
var
i : integer;
lIsWorkerStillBusy : boolean;
begin
    lIsWorkerStillBusy := true;
   for i := 0 to length(Workers)-1 do
    begin
        Workers[i].Start;
    end;
    while (lIsWorkerStillBusy) do
    begin
        lIsWorkerStillBusy := false;
        for i := 0 to length(Workers)-1 do
        begin
            if Workers[i].IsCalculated = false then
            begin
                lIsWorkerStillBusy := true;
            end;
        end;
        sleep(100);
    end;
    FindBestNetwork;
    IsAllWorkersDone := true;
end;

第二级线程

procedure cWorker.Execute;
begin
    IsCalculated := false;
    Network.UpdateFlows;
    Network.SolveNetWork;  //main simulation work
    CalculateTotalPower;
    IsCalculated := true;
end;

编辑 2

我创建它们全部暂停的原因是因为我将它们存储在一个数组中,并且在我开始它们之前,我首先创建了工人及其属性。我正在模拟空中网络场景。每个解决方案都是不同的布局,而每个工作人员是运行该布局的不同方式。

我必须先计算所有工作人员的启动属性,然后再启动它们。事后看来,我可以修改代码以在线程中执行此操作。它目前发生在主线程中。线程的创建发生在我粘贴在这里的一段代码之前。

我将它们全部保留在线程中的原因是我需要评估每个线程的结果。

【问题讨论】:

  • 大概问题的答案可以在代码中找到。
  • 我添加了一些代码。我试图只添加我认为有必要保持简短的部分。请告诉我您是否需要其他一些代码。
  • 谢谢,您的编辑保存了您的问题!
  • 我认为这与我电脑上的 4 个本机线程有关
  • @DavidHeffernan 是的,我知道。我想说的是基于任务的方法的作用,将是我的场景的理想选择。我只是对 Delphi 中不受支持的第三方库有过不好的经历。而且我已经看到 OTL 已经不支持 3 个最新的 Delphi 版本了。

标签: multithreading delphi


【解决方案1】:

这是你的问题:

for i := 0 to length(Solutions)-1 do
begin
    Solutions[i].Execute;   //start threads
end;

启动线程 - 这是在调用线程中执行Execute 方法。事实上,您一次并没有只运行 4 个线程,甚至没有运行一个 - 所有这些工作都将在主线程上按顺序完成。要恢复暂停的线程,您必须使用Solutions[i].Start

TThreadExecute 方法是在TThread 创建的工作线程上执行的特殊方法自动。当您创建TThread 时,此方法会自动在TThread 创建的工作线程上运行。如果您创建了挂起的线程,那么它只是等待您在开始这项工作之前唤醒线程。调用TThread.Start 方法可以实现这一点——触发底层工作线程开始执行.Execute 方法。

否则,Execute 方法和 TThread 的所有其他方法与属于某个类的任何其他普通方法没有区别。它们可以在任何直接调用它们的线程上执行。

在这种情况下,您似乎没有在创建和执行工作线程之间的主线程中做任何额外的工作。在这种情况下,除非您有明确的需要,否则您可以简单地创建未挂起的线程并让它们在创建时自动执行。

【讨论】:

  • 好的,所以代替执行,我应该调用 resume,它会在执行时“恢复”线程?
  • @blackwolfsa 我的错误 - Resume 已弃用。你应该改用.Start,但是是的,否则这就是你需要做的。
  • 实际上,我不明白您为什么要创建暂停的线程。这似乎毫无意义。为什么要创建一堆挂起的线程,然后立即启动它们?
  • @DavidHeffernan 同意,我也想知道。我会将建议添加到我的答案中。
  • @DavidHeffernan 也许他想同时运行线程(出于未说明的原因 - 也是一种不好的做法),并且初始化需要很多时间? - 再说一次,我只是猜测。 (这也可能是一些复制粘贴编程的产物。)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-06
相关资源
最近更新 更多