![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
|||
|
|||
|
Здравствуйте, мне в программе необходимо запускать функцию несколько раз, каждый раз в новом потоке, потоки должны работать одновременно, потоков может быть очень много.
Делаю так: Код:
procedure MyProcedure(a:integer); begin Form1.Memo1.Lines.Add(TimeToStr(Now)+' New thread, a:'+IntToStr(a)); sleep(1000*a); Form1.Memo1.Lines.Add(TimeToStr(Now)+'Thread with a:'+IntToStr(a)+' finished'); ExitThread(0); end; procedure TForm1.Button1Click(Sender: TObject); var dw:Dword; begin BeginThread(nil,0,@MyProcedure,Pointer(Random(5)),0,dw); end; initialization randomize; Всё работает, очень даже хорошо. Вопрос в следующем: как быть с функцией, которой нужно передать 2 или более параметров? Например: MyProcedure(a:integer; b:string; c:TDateTime); Как через BeginThread передать функции 2 или более параметров? Последний раз редактировалось ZXCCXZ, 01.06.2011 в 17:06. |
|
#2
|
||||
|
||||
|
через параметр Parameter: Pointer; можно передать все что хочешь. сделай его указателем на record.
|
|
#3
|
|||
|
|||
|
Цитата:
|
|
#4
|
|||
|
|||
|
А именно пробовал так:
Код:
type
MyP = record
a:integer;
b:string;
c:TDateTime;
end;
...
procedure MyProcedure(mp:MyP);
...
procedure TForm1.Button1Click(Sender: TObject);
var
dw:Dword;
mp:MyP;
begin
mp.a:=Random(5);
mp.b:='123';
mp.c:=Now;
BeginThread(nil,0,@MyProcedure,Pointer(mp),0,dw);
end;Ошибка следующая: [Error] Unit1.pas(50): Invalid typecast Последний раз редактировалось ZXCCXZ, 01.06.2011 в 17:14. |
|
#5
|
||||
|
||||
|
Код:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
PMethodLavrovoi = ^MethodLavrovoi;
MethodLavrovoi = record
h: THandle;
i: Integer;
s: String;
d: TDateTime;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure WMUSER(var Msg: TMessage); message WM_USER+$1001;
end;
var
Form1: TForm1;
FHandle: THandle;
FThreadID: THandle;
r: MethodLavrovoi;
implementation
{$R *.dfm}
function ThreadProc(Parameter: PMethodLavrovoi): Integer;
var
i: Integer;
begin
Parameter^.s:='MethodLavrovoi';
Parameter^.d:=Parameter^.d-1;
for i:=1 to Parameter^.i do
begin
Windows.Beep(1000, 100);
Sleep(500);
end;
PostMessage(Parameter^.h, WM_USER+$1001, 0, 0);
Result:=0;
EndThread(Result);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
r.h:=Handle;
r.i:=3;
r.s:='';
r.d:=Now;
FHandle:=BeginThread(nil, 0, @ThreadProc, @r, 0, FThreadID);
end;
procedure TForm1.WMUSER(var Msg: TMessage);
begin
ShowMessage(r.s+' '+DateToStr(r.d));
end;
end. |
|
#6
|
|||
|
|||
|
Однако есть проблема. Каждый раз при вызове функции передаются разные параметры. У вас переменная r объявлена глобальной и получается при одновременном выполнении нескольких экземпляров функции - они все используют одну переменную r. Мне нужно чтобы каждый раз функция запускалась в новом потоке с новыми параметрами (например как я писал Random(5) ).
Пробовал сделать переменную r локальной для процедуры клика на кнопке(procedure TForm1.Button1Click(Sender: TObject) , однако в результате при многократном нажатии Button1 - программа вылетает с ошибками AccesViolation. |
|
#7
|
||||
|
||||
|
ну не проблема:
Код:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
PMethodLavrovoi = ^MethodLavrovoi;
MethodLavrovoi = record
h: THandle;
n: Integer;
i: Integer;
s: ShortString;
d: TDateTime;
end;
TForm1 = class(TForm)
Button1: TButton;
Memo1: TMemo;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
procedure WMUSER(var Msg: TMessage); message WM_USER+$1001;
end;
var
Form1: TForm1;
FHandle: THandle;
FThreadID: THandle;
implementation
{$R *.dfm}
function ThreadProc(Parameter: PMethodLavrovoi): Integer;
begin
Sleep(Parameter^.i);
Parameter^.s:='MethodLavrovoi='+IntToStr(Parameter^.i);
Parameter^.d:=Parameter^.d-Parameter^.i;
PostMessage(Parameter^.h, WM_USER+$1001, WPARAM(Parameter), 0);
Result:=0;
EndThread(Result);
end;
{ TForm1 }
procedure TForm1.WMUSER(var Msg: TMessage);
var
p: PMethodLavrovoi;
begin
Msg.Result:=0;
p:=PMethodLavrovoi(Msg.WParam);
Memo1.Lines.Add(IntToStr(p^.n)+' '+p^.s+' '+DateTimeToStr(p^.d));
FreeMemory(p);
end;
procedure TForm1.Button1Click(Sender: TObject);
var
i: Integer;
p: PMethodLavrovoi;
begin
for i:=1 to 9 do
begin
p:=GetMemory(SizeOf(MethodLavrovoi));
p^.h:=Handle;
p^.n:=i;
p^.i:=(Random(9)+1)*10;
p^.s:='';
p^.d:=Now;
FHandle:=BeginThread(nil, 0, @ThreadProc, p, 0, FThreadID);
end;
end;
initialization
Randomize;
end.CloseHandle(FHandle); для всех потоков сам куда-нить воткнешь, я забыл про них совсем))) Последний раз редактировалось NumLock, 02.06.2011 в 08:47. |
| Этот пользователь сказал Спасибо NumLock за это полезное сообщение: | ||
harbor (05.05.2013)
| ||
|
#8
|
|||
|
|||
|
Я вот не понимаю, а чем стандартный TThrad не годится. По сути он делает все тоже самое. но предоставляет некоторый дополнительный сервис, не сильно перегружающий отдельный поток, но дающий простые способы для выполнения часто применяемых действий (синхронизация, автоматическое закрытие хэндлов и т.д).
А Винда вообще не любит очень много потоков, так что в их кол-ве ты не сильно выиграешь, отказавшись от TThread. Вообще, рекомендую задуматься о пуле потоков. |
|
#9
|
||||
|
||||
|
lmikle, надеюсь последнее примечание ко мне не относится, я всего лишь следую теме аватара "Создание потока с помощью BeginThread"?
![]() |