Как заставить мое приложение работать на нескольких ядрах? - PullRequest
0 голосов
/ 08 ноября 2018

У меня следующий код работает на Windows 10.

  function SingleProcessorMask(const ProcessorIndex: Integer): DWORD_PTR;
  begin
    Result:= 1; Result:= Result shl (ProcessorIndex);  //Make sure it works on processor 33 and up.
  end;

procedure TForm2.BtnCreateLookup5x5to3x3UsingSpeculativeExplorationClick(Sender: TObject);
var
  ThreadCount: integer;
  Threads: TArray<TThread>;
  CurrentProcessor: integer;
  i,a: integer;
  Done: boolean;
begin
  ThreadCount:= System.CpuCount;
  SetLength(Threads, ThreadCount);
  CurrentProcessor:= GetCurrentProcessorNumber;
  a:= 0;
  for i:= 1 to ThreadCount-1 do begin
    Threads[i]:= TThread.CreateAnonymousThread(procedure begin
      CreateLookupUsingGridSolver(i, ThreadCount);
    end);
    Threads[i].FreeOnTerminate:= false;
    if (CurrentProcessor = a) then Inc(a);  //Skip the current processor.
    Inc(a);
    //if (SetThreadAffinityMask(Threads[i].handle, SingleProcessorMask(a))) = 0 then RaiseLastOSError;  << fails here as well. 
    Threads[i].Start;
    if (SetThreadAffinityMask(Threads[i].handle, SingleProcessorMask(a))) = 0 then RaiseLastOSError;
  end; {for i}
  CreateLookupUsingGridSolver(0, ThreadCount, NewLookup);
  {Wait for all threads to finish}
  .....
  //Rest of the proc omitted to save space. 
end;

Я получаю ошибку 87, неверный параметр. Я совершенно уверен, что SingleProcessorMask правильно . Есть ли проблема с TThread.Handle?

Неважно, если я назову этот код запущенным от имени администратора, работающим на ноутбуке или работающим на i9. Результат всегда один и тот же.

И да, мне действительно нужно форсировать потоки, в противном случае все они объединяются в одном ядре.

UPDATE
Как только я исправляю сходство процессов с тем, чтобы оно соответствовало сходству систем, нет необходимости возиться с назначением каждого потока определенному ядру. В этом случае автоматическая обработка работает. Это делается с помощью:

GetProcessAffinityMask(GetCurrentProcess(), ProcessAffinityMask, SystemAffinityMask);
SetProcessAffinityMask(GetCurrentProcess(), SystemAffinityMask);
//Error checking omitted for brevity 

Ответы [ 2 ]

0 голосов
/ 08 ноября 2018

Похоже, вы пытаетесь создать отдельный поток для каждого ЦП , кроме"текущего" ЦП, на котором работает ваш обработчик OnClick. Но вы никогда не используете CPU 0 в своих аффинных масках, потому что вы увеличиваете a слишком рано. Но что более важно, маска сходства потока должна быть подмножеством маски сходства процесса, которая указывает процессоры, на которых разрешено запускать процесс:

Поток может работать только на тех процессорах, на которых может выполняться его процесс. Следовательно, маска соответствия потоков не может указывать 1 бит для процессора, когда маска соответствия процессов указывает 0 бит для этого процессора .

Маска сходства процесса сама является подмножеством маски сходства системы, которая указывает, какие ЦП установлены.

Таким образом, вероятной причиной вашей ошибки является то, что вы вычисляете маски сходства потоков, которые ОС отклоняет как недопустимые для вашего процесса.

Вместо этого попробуйте что-нибудь подобное (примечание: это не учитывает группы процессорных процессоров, если в ОС установлено более 64 процессоров):

procedure TForm2.BtnCreateLookup5x5to3x3UsingSpeculativeExplorationClick(Sender: TObject);
var
  ThreadCount, MaxThreadCount: integer;
  Threads: TArray<TThread>;
  i, CurrentProcessor: integer;
  ProcessAffinityMask, SystemAffinityMask, AllowedThreadMask, NewThreadMask: DWORD_PTR;      
  Thread: TThread;
  ...
begin
  if not GetProcessAffinityMask(GetCurrentProcess(), ProcessAffinityMask, SystemAffinityMask) then RaiseLastOSError;

  // optional: up the CPUs this process can run on, if needed...
  {
  if not SetProcessAffinityMask(GetCurrentProcess(), SystemAffinityMask) then RaiseLastOSError;
  ProcessAffinityMask := SystemAffinityMask;
  }

  AllowedThreadMask := DWORD_PTR(-1) and ProcessAffinityMask;
  CurrentProcessor := GetCurrentProcessorNumber;

  ThreadCount := 0;
  MaxThreadCount := System.CpuCount;
  NewThreadMask := 1;

  SetLength(Threads, MaxThreadCount);
  try
    for i := 0 to MaxThreadCount-1 do
    begin
      if (i <> CurrentProcessor) and //Skip the current processor.
         ((AllowedThreadMask and NewThreadMask) <> 0) then // is this CPU allowed?
      begin
        Thread := TThread.CreateAnonymousThread(
          procedure
          begin
            CreateLookupUsingGridSolver(...);
          end
        );
        try
          Thread.FreeOnTerminate := false;
          if not SetThreadAffinityMask(Thread.Handle, NewThreadMask) then RaiseLastOSError;
          Thread.Start;
        except
          Thread.Free;
          raise;
        end;
        Threads[ThreadCount] := Thread;
        Inc(ThreadCount);
      end;
      NewThreadMask := NewThreadMask shl 1;
    end;
    CreateLookupUsingGridSolver(...);

    // Wait for all threads to finish...
    // ...

  finally
    for i := 0 to ThreadCount-1 do
      Threads[i].Free;
  end;
end;
0 голосов
/ 08 ноября 2018

Есть два аргумента для SetThreadAffinityMask, дескриптор потока и маска. Из кода довольно ясно, что дескриптор потока действителен. Который оставляет маску. документация четко гласит следующее:

Если маска сходства потоков запрашивает процессор, который не выбран для маски сходства процессов, последний код ошибки будет ERROR_INVALID_PARAMETER.

Довольно сложно понять, что еще может объяснить поведение, о котором вы сообщаете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...