Форум: "Основная";
Текущий архив: 2005.09.11;
Скачать: [xml.tar.bz2];
ВнизВыполнить ПРОИЗВОЛЬНУЮ функцию(или метод) в отдельном потоке Найти похожие ветки
← →
Juice © (2005-08-22 20:10) [0]Есть у меня задумка облегчить себе работу созданием процедуры, которая будет выполнять передаваемую ей функцию или метод класса в отдельном потоке. Выглядеть это будет примерно так:
begin
ExecInThread(@func, ???params???, Res);
repeat
Application.ProcessMessages;
ProgressBar.Stepit;
until Res<>0
Сама процедура будет чем-то наподобие такого:
procedure ExecInThread(func : pointer, ??params??, Res:Variant);
var
MyThread : TMyThread;
begin
MyThread := TMyThread.Create(true);
... Передаем параметры в поток и запускаем его ...
Res := MyThread.Res;
MyThread.Free;
end;
procedure MyThread.Execute;
begin
... получить параметры и запустить процедуру ...
end;
Как вы и сами могли догадаться, что вопрос у меня вызывает способ передачи параметров, и способ запуска процедуры. Как лучше поступить при передаче параметров, в каком виде их передавать ? И как потом запустить процедуру? Мне в голову приходит только один подход - передать параметры в процедуру как вариантный массив, затем этот массив передать потоку, а тот уже на низком уровне(asm) засунет их в стек и вызовет требуемую функцию. Но это прокатить лишь для safecall, stdcall, cdecl и pascal функций, а как быть если нужно вызвать функцию register или метод класса ? Короче, полная каша в голове.
← →
Juice © (2005-08-22 20:16) [1]Ошибочка: procedure ExecInThread(func : pointer, ??params??, out Res:Variant);
← →
Defunct © (2005-08-22 20:17) [2]> Как вы и сами могли догадаться, что вопрос у меня вызывает способ передачи параметров
Через конструктор TThread.
TJob = procedure of object;
TExecuteThread = class(TThread)
private
fJob : TJob;
fOwner : HWND;
protected
procedure Execute;override;
public
constructor Create(AOwner: HWND; AJob : TJob);
end;
{ TExecuteThread }
constructor TExecuteThread.Create;
begin
if not Assigned( AJob ) then Exit;
inherited Create( True );
Priority := tpNormal;
FreeOnTerminate := True;
fOwner := AOwner;
fJob := AJob;
Resume
end;
procedure TExecuteThread.Execute;
begin
inherited;
if Assigned( fJob ) then fJob;
SendMessage( fOwner, WM_JOBDONE, Integer(Self),0);
end;
← →
Defunct © (2005-08-22 20:19) [3]> if not Assigned( AJob ) then Exit;
тут лучше не exit а raise.
← →
Juice © (2005-08-22 21:01) [4]
> Defunct © (22.08.05 20:17) [2]
Это не решение. Такой алгоритм не будет работать с
ПРОИЗВОЛЬНОЙ job-функцией (назовем ее так), в чем и состоит вся задача.
← →
Eraser © (2005-08-22 21:05) [5]Juice © (22.08.05 21:01) [4]
С произвольной функцией или методом не получиться, влюбом случае необходимо где-то объявить тип этой процедуры/метода, иначе вызвать не получиться.
← →
Juice © (2005-08-22 21:37) [6]
> С произвольной функцией или методом не получиться, влюбом
> случае необходимо где-то объявить тип этой процедуры/метода,
> иначе вызвать не получиться.
Ну, для не-register и методов я уже высказал свою "теорию вызова". А вообще вопрос можно сильно конкретезировать:
как вызвать метод, зная только его адрес и состав его параметров ? Думаю, что как-то можно. Например зачем тогда нужен TTObject.MethodAddress ? Где-то и кем-то он да используется!
← →
Eraser © (2005-08-22 21:42) [7]Juice © (22.08.05 21:37) [6]
Можно, давольно легко, на ассемблере. Единственное, что ещё нужно знать это способ передачи параметров.
← →
Defunct © (2005-08-22 21:42) [8]Juice © (22.08.05 21:01) [4]
Может ли любая произвольная функция знать о всех прихотях любой другой произвольной функции (чит. о ее параметрах)? Ответ - конечно же нет, т.к. для этого требуется обладать интеллектом. Т.о., для решения поставленной вами задачи необходимо написать функцию обладающую примитивным интеллектом - т.е. небольшой интерпретатор. Будет ли замедление при работе интерпретатора оправдано? - неизвестно.
С другой стороны, кто тебе мешает подготовить ряд функций без параметров, внутри которых вызывать ВСЁ, что твоя душа пожелает, и запускать все это отдельным потоком с помощью например [2]. Без потерь производительности на разбор параметров, и без потерь времени на изобретение бесполезного интерпретатора.
← →
Eraser © (2005-08-22 21:52) [9]Juice ©
Ещё как дополнение к сказаному Defunct"ом, можно сделать стандартную ф-ю со стандартными параметрами, например как SendMessage, т.е. "стандартизировать" вызов, но это конечно не всегда удобно.
← →
Juice © (2005-08-22 22:07) [10]
> С другой стороны, кто тебе мешает подготовить ряд функций
> без параметров, внутри которых вызывать ВСЁ, что твоя душа
> пожелает, и запускать все это отдельным потоком с помощью
> например [2]. Без потерь производительности на разбор параметров,
> и без потерь времени на изобретение бесполезного интерпретатора.
Это вполне приемлемое решение. Однако "без параметров" это уже совсем непрактично - ведь функции практически всегда оперируют некой информацией (данными) о которых им как-то нужно сообщить, и очень не удобно(иногда и невозможно) чтобы функция сама извлекала эти данные из каких-то внешних обьектов (глобальные переменные не использую за редкими исключениями). В общем случае нужно хоть один параметр передавать, пусть это будет просто pointer.
> Т.о., для решения поставленной вами задачи необходимо написать
> функцию обладающую примитивным интеллектом - т.е. небольшой
> интерпретатор. Будет ли замедление при работе интерпретатора
> оправдано? - неизвестно
Думаю, что для меня это будет оправдано:
ExecInThread(@func, ???params???, Res);
repeat
Application.ProcessMessages;
ProgressBar.Stepit;
until Res<>0
Такой и подобный код слишком часто (настолько часто, чтобы стала ощутима разница в быстродействии) врядли кому-то понадобиться вызывать. Да и вообще потоки плодить тоже как-то плохо.
А "интерперетатор" меня все-таки интересует, просто из любопытства. Да и если получиттся , то ИМХО это будет более простой и красивый способ для использования - одна строчка и все.
> Можно, давольно легко, на ассемблере. Единственное, что
> ещё нужно знать это способ передачи параметров.
ОК, пусть нужно вызывать только методы , т.е. способ передачи - register. Насколько я себе представляю, первым параметром нужно передать ссылку на сам обьект - чтобы обеспечить Self методу, а затем уже параметры. Но как ? Через регистры, параметры которые "не лезут" в регистры через стек? Для меня слишком сложно и запутанно. Можно по-подробнее ?
← →
Juice © (2005-08-22 22:09) [11]...о реализации
← →
Eraser © (2005-08-22 22:14) [12]Juice © (22.08.05 22:07) [10]
"Команды процесора.
Ура, начиная с шестой версии, в популярном продукте Borland реализована поддержка всех команд процессора, включая команды расширений MMX, SSE, 3DNow! Теперь нет необходимости вместо простой команды rdtsc писать dw 310Fh .
Доступ к переменным.
Delphi позволяет легко обращаться по имени к глобальным или локальным переменным:
var
i : integer;
begin
i:=0;
asm
mov eax,i
inc eax
mov i,eax
end;
end;
Доступ к параметрам.
К переменным, передаваемым процедуре в качастве параметров доступ осуществляется также легко:
procedure SomeProc(i : integer);
begin
asm
mov eax,i
inc eax
mov i,eax
end;
and;
Передача параметров по ссылке.
Если параметр процедуры или функции объявляется как var, то вместо значения переменной передается указатель на эту переменную. Поэтому внутри ассемблерного блока этот параметр будет представлять собой 32-разрядный указатель вместо собственно переменной. Поэтому обращаться к параметру, переданному как var надо следующим образом:
procedure SomeProc(var i : integer);
begin
asm
mov eax,i
inc dword ptr [eax]
end;
end;
Регистровое соглашение о вызове.
В языке Object Pascal, использующемся в Delphi, по умолчанию действует регистровое соглашение о вызове. Согласно этому соглашению, первые три 32-разрядных параметра передаются в регистры eax,edx и ecx. Следовательно, если функция объявлена следующим образом
function SomeFunc(i1, i2, i3 : integer): integer;
то можно расчитывать, что переменная i1 содержится в регистре eax, i2 - в edx, i3 - в ecx.
Если объявлен некий метод
procedure TSomeObject.SomeProc(i1, i2 : integer);
то i1 передается в edx, i2 - в ecx, а в eax передается неявно заданный параметр Self!
Доступ к полям записи.
Обращение к полям записи также достаточно просто:
type
TSomeRec = record
i : integer;
c : char;
end;
procedure SomeProc(var SomeRec : TSomeRec);
begin
asm
mov [eax].TSomeRec.i, 33
mov [eax].TSomeRec.c,"a"
end;
end;
Локальные метки.
Хотя использование меток и считается дурным тоном в программировании на языках высокого уровня, в ассеблерных программах без них не обойтись. Внутри блока asm..end можно, без предварительного объявления, использовать метки, начинающиеся с символа "@".
Сохранение регистров.
В ассемблерных процедурах и функциях нужно сохранять регистры EDI, ESI, ESP, EBP, and EBX и свободно оперировать регистрами EAX, ECX, and EDX.
Вызов динамических и виртуальных методов.
Существуют две директивы для доступа к динамическим и виртуальным метолам из ассемблерных вставок.
VMTOFFSET - возвращает смещение (в байтах) указателя виртуального метода относительно начала таблицы виртуальных методов (VMT).
DMTINDEX - возвращает индекс динамического метода в таблице динамических методов.
Примеры вызовов виртуального и динамического методов:
procedure CallDynamicMethod(e: TExample);
asm
push esi
mov eax,e
mov esi, DMTINDEX TExample.DynamicMethodы
call System.@CallDynaInst
pop esi
end;
procedure CallVirtualMethod(e: TExample);
asm
mov eax, e
mov edx, [eax]
call dword ptr [edx + VMTOFFSET TExample.VirtualMethod]
end;"
← →
Eraser © (2005-08-22 22:16) [13]Juice © (22.08.05 22:09) [11]
Всё же советую не лезть в степь.
Лучше унифицируй функцию, т.е. оформляй везде одинакого.
← →
Juice © (2005-08-23 00:36) [14]
> Всё же советую не лезть в степь.
> Лучше унифицируй функцию, т.е. оформляй везде одинакого.
После [12] как-то перехотелось :) Зато уяснились некоторые моменты. Всем биг сэнкс!
← →
Юрий Зотов © (2005-08-23 00:43) [15]array of const
Это произвольное количество произвольных параметров. Вызываемая функция конкретна, поэтому она сама с ними разберется.
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2005.09.11;
Скачать: [xml.tar.bz2];
Память: 0.51 MB
Время: 0.01 c