SetProcessAffinityMask - выбрать более одного процессора? - PullRequest
8 голосов
/ 31 января 2012

Как я могу использовать 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);

Например, выберите любой из процессоров для процесса, как показано в диспетчере задач.

Как мне это сделать, используя Array, Set или что-то еще? Я не могу заставить его работать с несколькими значениями.

Спасибо.

Ответы [ 2 ]

13 голосов
/ 31 января 2012

Это битовая маска, как описано в документации .

Маска сродства процесса - это битовый вектор, в котором каждый бит представляет логический процессор, на котором разрешено запускать потоки процесса.

  • Процессор 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, но стоит сделать все правильно, чтобы облегчить перенос любого будущего кода.

8 голосов
/ 31 января 2012

Это 32-битная битовая маска на моем XE (но она может быть 64-битной на 64-битном XE2!)

Просто определите набор [0..31], где 0 = процессор 1 и т. Д..

Затем введите маску для результата.

Итак

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)); 
...