SetProcessAffinityMask - 选择多个处理器?

时间:2012-01-31 11:35:02

标签: delphi delphi-xe

如何使用SetProcessAffinityMask选择多个逻辑处理器?

在Windows任务管理器中,您可以这样做:

enter image description here

我更新了我的CreateProcess程序来执行此操作:

type
  TProcessPriority = (ptLow         = $00000040,
                      ptBelowNormal = $00004000,
                      ptNormal      = $00000020,
                      ptAboveNormal = $00008000,
                      ptHigh        = $00000080,
                      ptRealtime    = $00000100);

procedure RunProcess(FileName: string; Priority: TProcessPriority);
var
  StartInfo: TStartupInfo;
  ProcInfo: TProcessInformation;
  CmdLine: string;
  Done: Boolean;
begin
  FillChar(StartInfo, SizeOf(TStartupInfo), #0);
  FillChar(ProcInfo, SizeOf(TProcessInformation), #0);
  StartInfo.cb := SizeOf(TStartupInfo);

  CmdLine := FileName;
  UniqueString(CmdLine);
  try
    Done := CreateProcess(nil, PChar(CmdLine), nil, nil, False,
                          CREATE_NEW_PROCESS_GROUP + Integer(Priority),
                          nil, nil, StartInfo, ProcInfo);
    if Done then
    begin
      // Todo: Get actual cpu core count before attempting to set affinity!
      // 0 = <All Processors>
      // 1 = CPU 0
      // 2 = CPU 1
      // 3 = CPU 2
      // 4 = CPU 3
      // 5 = CPU 5
      // 6 = CPU 6
      // 7 = CPU 6
      // 8 = CPU 7

      // this sets to CPU 0 - but how to allow multiple parameters to
      // set more than one logical processor?
      SetProcessAffinityMask(ProcInfo.hProcess, 1); 
    end else
      MessageDlg('Could not run ' + FileName, mtError, [mbOk], 0)
  finally
    CloseHandle(ProcInfo.hProcess);
    CloseHandle(ProcInfo.hThread);
  end;
end;

请注意我在那里发表的评论。最好更新我的过程以包含一个新的Affinity参数,我可以将其传递给SetProcessAffinityMask。

出于显而易见的原因,调用其中任何一个都不会选择相应的处理器,它们会给出我想要做的事情的想法:

SetProcessAffinityMask(ProcInfo.hProcess, 1 + 2); 
SetProcessAffinityMask(ProcInfo.hProcess, 1 and 2);

例如,为进程选择任何CPU,如任务管理器中所示。

我应该如何使用数组,集合或其他内容?我无法使用多个值。

感谢。

2 个答案:

答案 0 :(得分:13)

它是documentation中描述的位掩码。

  

进程关联掩码是一个位向量,其中每个位表示允许进程的线程运行的逻辑处理器。

  • 处理器0为$ 01。
  • 处理器1是$ 02。
  • 处理器2是$ 04。
  • 处理器3是$ 08。
  • 处理器4是10美元。

等等。您可以使用逻辑or来组合它们。因此,处理器0和1将$01$02等于$03

我会使用移位运算符shl为特定处理器创建值。像这样:

function SingleProcessorMask(const ProcessorIndex: Integer): DWORD_PTR;
begin
  //When shifting constants the compiler will force the result to be 32-bit
  //if you have more than 32 processors, `Result:= 1 shl x` will return
  //an incorrect result.
  Result := DWORD_PTR(1) shl (ProcessorIndex); 
end;

您可以轻松扩展此选项,以便为循环中使用逻辑or的处理器列表生成掩码。

function CombinedProcessorMask(const Processors: array of Integer): DWORD_PTR;
var
  i: Integer;
begin
  Result := 0;
  for i := low(Processors) to high(Processors) do
    Result := Result or SingleProcessorMask(Processors[i]);
end;

您可以测试像这样的位掩码的处理器:

function ProcessorInMask(const ProcessorMask: DWORD_PTR; 
  const ProcessorIndex: Integer): Boolean;
begin
  Result := (SingleProcessorMask(ProcessorIndex) and ProcessorMask)<>0;
end;

注意:我正在使用DWORD_PTR,因为对于64位目标,位掩码是64位宽。在XE上,这种细微差别并不重要,但是让未来的代码移植变得更容易,这是值得的。

答案 1 :(得分:8)

这是我的XE上的32位位掩码(但它可能是64位XE2上的64位!)

只需定义一组[0..31],其中0 = cpu 1等。

然后将结果键入掩码为dword。

所以

var 
  cpuset  : set of 0..31;

begin
  cpuset:=[1,2]; // cpus 2 and 3
  include (cpuset,5); // add cpu 6
  SetProcessAffinityMask(ProcInfo.hProcess, dword(cpuset));