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