|
|
Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
|
Опции темы | Поиск в этой теме | Опции просмотра |
#1
|
|||
|
|||
Создание потока с помощью BeginThread
Здравствуйте, мне в программе необходимо запускать функцию несколько раз, каждый раз в новом потоке, потоки должны работать одновременно, потоков может быть очень много.
Делаю так: Код:
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"?
Пишу программы за еду. __________________ |