runewalsh спасибо! После
runewalsh писал(а):Уф. Ну, похоже, ты не знаешь некоторых вещей и по-хорошему тебе нужно объяснять их с нуля
началось именно то, что мне и нужно  
 Полдня сегодня мучался.
 ты берёшь указатель на указатель
Понял! WaitForMultipleObjects ожидает объекты из массива TWOHandleArray на ура. Понял почему это
Лучше, но более громоздко
64 хэндла. А если больше надо будет, то можно и еще такой же сделать и заполнять один за другим. А можно и ограничение при вводе кол-ва потоков поставить, объяснив в отчете - почему
Не сразу понял
Нет, это просто пример правильной работы с WaitForMultipleObjects (которая тебе не нужна хд).
Но похоже начинаю понимать. Мы в душе не... знаем сколько потоков у нас работают на данный момент.
Начал всяко хиромантить... Вспоминая примеры. И пришел к выводу, что я один черт не до конца понял КАК РАБОТАЕТ QueueUserAPC
1. Создали пул (массив потоков)
2. Усыпили эти потоки
3. С помощью QueueUserAPC запустили один из спящих потоков на ф-цию
4. Что то в этой ф-ции поток сделал, и потом 
ЧТО? будет соответствовать заданию? Усыпить его снова SleepEx? Я там код, кстати, не до конца понял, спрошу еще. Если нет, то 
ЧТО по природе ф-ции QueueUserAPC он делает? Все примеры даны линейно, задание, напомню
При обработке массива данных пулом потоков, завершив обработку одного элемента массива данных, освободившийся в пуле поток переходит к обработке следующего необработанного элемента. 
то есть мы должны их ротировать пока не выполним задание. Если я вообще этот чертов документ понимаю.  

 По природе QueueUserAPC не запустит же поток, который уже работает? Ротация (итерация) пойдет дальше...
И ни фига что то дебит с кредитом не бъётся. Оставил свои закомментированные изыскания. Видно, что иду уже по кругу  
 - Код: Выделить всё
 {$mode objfpc} {$h+}
uses windows;
TYPE
DBThreads=   record
ID         :Cardinal;
end;
var
i,n,count   :word;
Threads      :TWOHandleArray;
ThreadIDs   :array of DBThreads;
Sem         :HANDLE;
Status,Zadacha,Zadanie      :LongWord;
runningTasks:integer; // = 0
allTasksCompleted: PRTLEvent;
procedure PrepareTaskQueuing;
   begin
      if InterlockedIncrement(runningTasks) = 1 then RTLEventResetEvent(allTasksCompleted);
   end;
   procedure NoteTaskCompleted;
   begin
      if InterlockedDecrement(runningTasks) = 0 then RTLEventSetEvent(allTasksCompleted);
   end;
function QueueUserAPC(pfnAPC:Pointer;hThread:HANDLE;dwData:ULONG_PTR):DWORD; 
stdcall; external 'Kernel32.dll';
function ThreadFunction(lpParameter: Pointer): Cardinal; stdcall;
begin
  while True do
    SleepEx(INFINITE, TRUE);
  Exit(0);
end;
FUNCTION PrintInteger(Param: integer):ptrint; stdcall;
var
ID:Cardinal;
First:bool;
Potok,a:integer;
q:pointer;
begin
   WaitForSingleObject(Sem, INFINITE);
   inc (Zadacha);
   Writeln('Задача: ',Zadacha,' выполнена потоком c ID ',Param);      
   ReleaseSemaphore(Sem, 1, nil);
   ThreadFunction(q);
   writeln(GetCurrentThreadId,' проснулся');
   NoteTaskCompleted;
   PrintInteger:=0;
end;
begin
   write('Сколько потоков будет в пуле? ');
   readln(n);
   write('Сколько задач нужно выполнить? ');
   readln(Zadanie);
   SetLength(ThreadIDs,n);   
   for i:=0 to n-1 do
   Threads[i] := CreateThread(nil, 0, @ThreadFunction, nil, 0, ThreadIDs[i].ID);
   Sem := CreateSemaphore(nil, 1, 1, nil);
   allTasksCompleted := RTLEventCreate;
      if Zadacha<>Zadanie then 
{    begin
      if count=n then count:=0;
      QueueUserAPC(@PrintInteger,Threads[count],ThreadIDs[count].ID);
      inc (count);
   end; }
   repeat
      writeln('Выполнено ',Zadacha,' задач');
      if count=n then count:=0;
      PrepareTaskQueuing;
      QueueUserAPC(@PrintInteger,Threads[count],ThreadIDs[count].ID);
      inc (count);
   until Zadacha=Zadanie;
{    repeat
      count:=0;
         for i:=0 to n-1 do
      begin
         GetExitCodeThread(Threads[i], Status);
         if (Status<>0) and (Status<>259) then inc(count);
      end;
   until count=0; }
//   WaitForMultipleObjects(count, @Threads, TRUE, INFINITE );
   RTLEventWaitFor(allTasksCompleted);
   writeln ('Все потоки в домике');
   for i:=0 to n-1 do CloseHandle(Threads[i]);   
   RTLEventDestroy(allTasksCompleted);
   writeln ('Все потоки закрыты');
   readln
end.
ВОПРОСЫ ПО КОДУ1. Что дают директивы компилятора {$mode objfpc} {$h+}?
2. Почему в ThreadFunction сразу начинается проверка какой то переменной, или я даже хз что это такое - True? Что это за проверка циклом while, чего?
3. Если соблюдается это условие, то поток усыпляем. Как то там сигнально, но короче с возможностью его использования QueueUserAPC в дальнейшем. Почему у Exit есть параметр (0), что он вообще делает? И в целом, чтоб, может быть до конца понять - условное ветвление тут не сработало бы что ли?