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), что он вообще делает? И в целом, чтоб, может быть до конца понять - условное ветвление тут не сработало бы что ли?