Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

delphi - SetProcessAffinityMask - Select more than one processor?

How can I use SetProcessAffinityMask to select more than one logical processor?

In Windows Task Manager you can do this as an example:

enter image description here

I updated my CreateProcess procedure to do this:

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;

Note the comments I put in there. It would be good to update my procedure to include a new Affinity parameter which I can pass to SetProcessAffinityMask.

Calling any of these won't select the corresponding processors for obvious reasons, they give the idea of what I am wanting to do:

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

eg, select any of the CPU's for a process, as shown in Task Manager.

How should I do this, using an Array, Set or something else? I cannot get it to work with multiple values.

Thanks.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It is a bitmask as described in the documentation.

A process affinity mask is a bit vector in which each bit represents a logical processor on which the threads of the process are allowed to run.

  • Processor 0 is $01.
  • Processor 1 is $02.
  • Processor 2 is $04.
  • Processor 3 is $08.
  • Processor 4 is $10.

And so on. You can use logical or to combine them. So processors 0 and 1 would be $01 or $02 which equals $03.

I would use the shift operator shl to create values for specific processors. Like this:

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;

You can readily extend this to generate masks for lists of processors using logical or in a loop.

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;

You can test for a processor being in a bit mask like this:

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

Note: I'm using DWORD_PTR because for 64 bit targets the bitmask is 64 bits wide. That nuance doesn't matter for you on XE but it's worth getting it right to make any future code porting easier.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...