为什么线程甚至在抢占式多任务操作系统上挨饿(Windows 7)

时间:2012-08-13 21:47:56

标签: multithreading delphi winapi delphi-7 multitasking

我写了一个Win32应用程序(在Delphi-7中使用TThread类是32位)来创建100个线程。恢复时的每个线程将连续(在循环中)递增与线程对象相关联的64位计数器(因此不会锁定或共享数据)。

如果让系统运行10到15秒并在此之后停止,则应该在每个线程中看到大致相同的计数。但我观察到的是,81个线程在4亿个循环下运行,其余循环超过9.5亿次。与最快的2111万相比,最慢的线程只有2.3亿。

根据MSDN,抢先式多任务处于线程级别(不是进程级别),因此我的每个线程都应该以循环方式获得其时间片。我在这里错过了什么,为什么会出现这种差异?

Edit1:机器配置:启用超线程的Intel i7 Quad Core 3.4GHz(一次启动8个活动线程)。运行Windows-7 64位专业版(测试应用程序是32位)

Edit2(线程代码):测试应用程序是在打开优化的情况下构建的,没有任何调试信息。在IDE之外运行测试应用程序。

type

  TMyThread = class(TThread)
  protected
    FCount: Int64;
  public
    constructor Create;
    procedure Execute; override;
    property Count: Int64 read FCount;
  end;


{ TMyThread }

constructor TMyThread.Create;
begin
  inherited Create(True);
  FCount := 0;
end;  

procedure TMyThread.Execute;
begin
  inherited;
  while not Terminated do
  begin
    Inc(FCount);
  end;
end;

4 个答案:

答案 0 :(得分:10)

循环调度是内核的一个明显策略。然而,这不是Windows调度程序的工作方式。过去,在Windows 9x时代,它曾经是一个能够为各种虚拟机提供相同时间的调度程序。但是在Dave Cutler的小组开始的NT分支中,调度完全基于优先级

无论哪个线程具有最高优先级,都会得到cpu。 Windows中还有另一块代码,它们具有线程优先级,并根据线程创建时的默认优先级进行修改。该代码知道像拥有一个位于前台的窗口的线程之类的东西。或者正在等待已发出信号的同步对象的线程。或者是试图解决优先级倒置问题的更奇怪的调度问题。随机给一个线程一个机会运行,即使它没有轮到它。

专注于首先编写理智的代码。开始一百个线程并不是一件非常理智的事情。您正在尝试消耗机器实际上没有的资源,没有人拥有一百个内核的机器。然而。两个人的权力,先得到一台128核的机器。

答案 1 :(得分:3)

我已复制并确认您的结果。此外,禁用线程优先级提升不会更改分发。 GetThreadTimes报告具有较高值的​​线程占用更多UserTime,反之亦然,而KernelTime似乎与值无关。

Thread 97: 1081,5928 Ke:0 Us:25116161
Thread 98: 1153,8029 Ke:0 Us:26988173
Thread 99: 704,6996  Ke:0 Us:16848108
显然,有些线程比其他线程更频繁地运行。

我没有将结果绘制成图,但我认为我们看到的是Normal distribution,这意味着结果取决于许多因素,其中一些因素是随机的。

我尝试禁用超线程(这样可以平滑结果),然后为每个线程分配一个物理处理器(使用SetThreadAffinityMask)。在第二种情况下,价值观彼此更加接近。

SetThreadAffinityMask(Self.Handle, 1 shl (FIndex mod 4));

我可以理解如何在超线程系统上运行可以使某些线程“运气不好”:它们被安排与同一物理处理器上的其他线程竞争,并且由于"soft affinity"到这个虚拟核心他们一次又一次地依靠它,因此得分低于其他人。

但至于为什么将每个线程绑定到固定核心有助于非超线程系统,我不知道。

可能还涉及其他随机事项,例如其他进程对核心的活动。如果与同一核心关联的某个其他进程的线程突然醒来并开始做一些(相对)繁重的工作,则线程可能会“不吉利”。

所有这一切都在猜测。

答案 2 :(得分:1)

Windows 7专为用户设计。当你的第一个线程想要工作时,操作系统给它一个时间片。你,用户,毕竟是刚开始的。当第50个线程连续(来自同一个进程!)想要工作时,更高优先级的线程(由Windows 7本身控制的后台进程)介入。这种情况正在发生,使得某些< / strong> threads luckier

您和我真的不希望个人操作系统根据用户土地流程的奇想分发CPU时间。我很想知道2008 R2服务器如何处理这个问题。您还可以使用“高级”选项卡设置:“选择如何分配处理器资源”。

答案 3 :(得分:-1)

这里有一些很好的推理......但是有一些功能需要考虑。 Windows正在尝试使用软件进行多任务处理。 您的硬件不是多任务处理,它使用电源来执行并行处理系统所能做的事情。 在Windows下,它优先考虑。在很多方面......令人困惑。

让我以这种方式解释。 我有一个小程序,它可以监视我的内核供他们使用。 当Windows加载时,您会认为所有核心都会被使用。不。 当窗口加载时,其他核心开始使用。 然后你会想,当Windows加载它会加速加载,因为它可以访问核心。它不加速。它没有使用核心是FULL速度加载更快。 即使Windows在加载和运行时将程序推送到1核EACH,它也可以等待它们完成。如果它使用所有内核来处理每个程序,它使用软件(比硬件慢大约100倍)来组装另一端的部件。 很久以前,英特尔想要将硬件更改为并行处理,而MS表示“不”,因为他们的软件不是为它而设计的。他们现在正试图将基于串行的硬件设计推向N点。即使在MS购买了NT软件之后。最近他们忘了使用它的大部分设计。 需要进行一些硬件更改。需要编程语言更改(MS创建编程语言),并且需要再次设计Windows的核心。没有改变。它需要回头并从头开始。祝你好运。 告诉你这个想法有多久了...... VIVA La'Amiga。