我如何在 delphi 项目中执行两个线程
how i can execute two threads in delphi project
我的项目包含两个执行不同任务的过程,
然后我在计时器中执行每个线程。
我的问题是...当我 运行 项目时,计时器启动。
线程无法正常工作。
为什么?
而且,我可以在同一个项目中使用两个或更多线程吗?
注意:我很想用线程,需要有线程的解决方案
这是我没有线程的代码。
procedure TForm1.Timer1Timer(Sender: TObject);
var
i : integer;
begin
for i := 0 to 50 do
begin
Memo1.Lines.Add(IntToStr(i));
sleep(500);
end;
end;
procedure TForm1.Timer2Timer(Sender: TObject);
var
k : integer;
begin
for k := 0 to 50 do
begin
Memo2.Lines.Add(IntToStr(k));
sleep(500);
end;
end;
end.
有线程:
type
TThread_Timer2 = class(TThread)
protected
procedure Execute; override;
end;
type
TThread_Timer3 = class(TThread)
protected
procedure Execute; override;
end;
procedure TThread_Timer2.Execute;
var
i : integer;
begin
for i := 0 to 50 do
begin
Memo1.Lines.Add(IntToStr(i));
sleep(500);
end;
end;
procedure TThread_Timer3.Execute;
var
k : integer;
begin
for k := 0 to 50 do
begin
Memo2.Lines.Add(IntToStr(k));
sleep(500);
end;
end;
procedure TForm1.Timer2Timer(Sender: TObject);
var
thd : TThread_Timer2;
begin
thd := TThread_Timer2.Create(true);
try
thd.FreeOnTerminate := true;
thd.Priority := tpHighest;
finally
thd.Resume;
end;
end;
procedure TForm1.Timer3Timer(Sender: TObject);
var
trhd : TThread_Timer3;
begin
trhd := TThread_Timer3.Create(true);
try
trhd.FreeOnTerminate := true;
trhd.Priority := tpHighest;
finally
trhd.Resume;
end;
end;
您可以使用任意多的线程。但是,您必须遵守 VCL 的规则。具体来说,您必须只能从主线程访问 VCL 组件。您的代码违反了该规则。
每当您想从线程访问 VCL 组件时,请使用 TThread.Synchronize
或 TThread.Queue
方法在主线程上执行代码。
看看你的代码,如果你真的想在每次触发计时器时创建一个新线程,我会感到惊讶。这真的是你打算做的吗?并且在计时器过程中使用 try/finally
充其量是可疑的。如果引发异常,你真的想启动线程吗?编译器应该告诉您 Resume
方法已被弃用,您应该改用 Start
。您是否启用了编译器提示和警告?您几乎肯定不希望修改线程优先级。如果使用不当,可能会导致各种问题,就像这里的情况一样。
综上所述,如果您愿意并避免使用任何线程,您可以使用计时器完美地编写代码。您需要声明几个计数器,每次定时器过程触发时它们都会递增。例如:
type
TForm1 = class(TForm)
....
private
FCounter1: Integer;
....
end;
然后当你想开始计数时,你初始化计数器并启动计时器:
FCounter1 := 0;
Timer1.Enabled := True;
每当计时器触发您的增量计数器时。当计数器达到上限值时停止计数器。
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Memo1.Lines.Add(IntToStr(FCounter1));
inc(FCounter1);
if FCounter1 > 50 then
Timer1.Enabled := False;
end;
您的代码,已更正为仅在主线程中执行 UI 操作。它对我有用:
TThread_Timer2 = class(TThread)
private
FVar: Integer;
procedure UpdateMemo;
protected
procedure Execute; override;
end;
TThread_Timer3 = class(TThread)
private
FVar: Integer;
procedure UpdateMemo;
protected
procedure Execute; override;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
thd : TThread_Timer2;
begin
thd := TThread_Timer2.Create(true);
try
thd.FreeOnTerminate := true;
thd.Priority := tpHighest;
finally
thd.Resume;
end;
end;
procedure TThread_Timer2.Execute;
var
i : integer;
begin
for i := 0 to 50 do
begin
FVar := i;
Synchronize(UpdateMemo);
sleep(500);
end;
end;
procedure TThread_Timer3.Execute;
var
k : integer;
begin
for k := 0 to 50 do
begin
FVar := k;
Synchronize(UpdateMemo);
sleep(500);
end;
end;
procedure TForm1.Timer2Timer(Sender: TObject);
var
trhd : TThread_Timer3;
begin
trhd := TThread_Timer3.Create(true);
try
trhd.FreeOnTerminate := true;
trhd.Priority := tpHighest;
finally
trhd.Resume;
end;
end;
procedure TThread_Timer2.UpdateMemo;
begin
Form1.Memo1.Lines.Add(IntToStr(FVar));
end;
procedure TThread_Timer3.UpdateMemo;
begin
Form1.Memo2.Lines.Add(IntToStr(FVar));
end;
我没有更改您代码中的任何其他内容,但请仔细阅读 David 的回答。里面有备注要注意
亚当,
如果使用 Parallel 库会更容易。您的初始程序将是这样的:
proceedure TForm1.Timer1Timer(Sender: TObject);`
begin
TTask.Run(procedure
var
i: integer;
begin
for i:=0 to 50 do
begin
TThread.Synchronize(TThread.CurrentThread,
procedure
begin
Memo1.Lines.Add(i.ToString);
Sleep(500);
end);
end;
end);
end;
根据@GabrielF的回复,我添加了一个ttimer,并做了一个完整的代码复制过去:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
procedure Timer1Timer(Sender: TObject);
procedure Timer2Timer(Sender: TObject);
public
{ Public declarations }
end;
TThread_Timer2 = class(TThread)
private
FVar: Integer;
procedure UpdateMemo;
protected
procedure Execute; override;
end;
TThread_Timer3 = class(TThread)
private
FVar: Integer;
procedure UpdateMemo;
protected
procedure Execute; override;
end;
var
Form1: TForm1;
Memo1:TMemo;
Memo2:TMemo;
Timer: TTimer;
implementation
{$R *.dfm}
procedure TForm1.Timer1Timer(Sender: TObject);
var
thd : TThread_Timer2;
begin
thd := TThread_Timer2.Create(true);
try
thd.FreeOnTerminate := true;
thd.Priority := tpHighest;
finally
thd.Resume;
end;
end;
procedure TThread_Timer2.Execute;
var
i : integer;
begin
for i := 0 to 10 do
begin
FVar := i;
Synchronize(UpdateMemo);
sleep(1000);
end;
end;
procedure TThread_Timer3.Execute;
var
k : integer;
begin
for k := 0 to 10 do
begin
FVar := k;
Synchronize(UpdateMemo);
sleep(1000);
end;
end;
procedure TForm1.Timer2Timer(Sender: TObject);
var
trhd : TThread_Timer3;
begin
trhd := TThread_Timer3.Create(true);
try
trhd.FreeOnTerminate := true;
trhd.Priority := tpHighest;
finally
trhd.Resume;
end;
end;
procedure TThread_Timer2.UpdateMemo;
begin
Memo1.Lines.Add(IntToStr(FVar));
end;
procedure TThread_Timer3.UpdateMemo;
begin
Memo2.Lines.Add(IntToStr(FVar));
end;
procedure TForm1.FormCreate(Sender: TObject);
var bt1,bt2: TButton;
begin
Form1.Width:=440;
Form1.Height:=500;
//
Memo1 := TMemo.Create(nil);
Memo1.Width := 200;
Memo1.Height := 400;
Memo1.Top := 30;
Memo1.Parent := Form1;
//
Memo2 := TMemo.Create(nil);
Memo2.Width := 200;
Memo2.Height := 400;
Memo2.Top := 30;
Memo2.Left := 210;
Memo2.Parent := Form1;
//
Timer := TTimer.Create(nil);
Timer.Interval := 10000;
Timer.OnTimer := Timer2Timer;
Timer.Enabled := true;
//
bt1 := TButton.Create(nil);
bt1.Width := 200;
bt1.OnClick := Timer1Timer;
bt1.Caption := 'Create thread Memo1';
bt1.Parent := Form1;
//
bt2 := TButton.Create(nil);
bt2.Left:=210;
bt2.Width := 200;
bt2.OnClick := Timer2Timer;
bt2.Caption := 'Create thread Memo2';
bt2.Parent := Form1;
end;
end.
也许它对某人有帮助。我是在Delphi7上写测试的。
我的项目包含两个执行不同任务的过程, 然后我在计时器中执行每个线程。
我的问题是...当我 运行 项目时,计时器启动。 线程无法正常工作。
为什么?
而且,我可以在同一个项目中使用两个或更多线程吗?
注意:我很想用线程,需要有线程的解决方案
这是我没有线程的代码。
procedure TForm1.Timer1Timer(Sender: TObject);
var
i : integer;
begin
for i := 0 to 50 do
begin
Memo1.Lines.Add(IntToStr(i));
sleep(500);
end;
end;
procedure TForm1.Timer2Timer(Sender: TObject);
var
k : integer;
begin
for k := 0 to 50 do
begin
Memo2.Lines.Add(IntToStr(k));
sleep(500);
end;
end;
end.
有线程:
type
TThread_Timer2 = class(TThread)
protected
procedure Execute; override;
end;
type
TThread_Timer3 = class(TThread)
protected
procedure Execute; override;
end;
procedure TThread_Timer2.Execute;
var
i : integer;
begin
for i := 0 to 50 do
begin
Memo1.Lines.Add(IntToStr(i));
sleep(500);
end;
end;
procedure TThread_Timer3.Execute;
var
k : integer;
begin
for k := 0 to 50 do
begin
Memo2.Lines.Add(IntToStr(k));
sleep(500);
end;
end;
procedure TForm1.Timer2Timer(Sender: TObject);
var
thd : TThread_Timer2;
begin
thd := TThread_Timer2.Create(true);
try
thd.FreeOnTerminate := true;
thd.Priority := tpHighest;
finally
thd.Resume;
end;
end;
procedure TForm1.Timer3Timer(Sender: TObject);
var
trhd : TThread_Timer3;
begin
trhd := TThread_Timer3.Create(true);
try
trhd.FreeOnTerminate := true;
trhd.Priority := tpHighest;
finally
trhd.Resume;
end;
end;
您可以使用任意多的线程。但是,您必须遵守 VCL 的规则。具体来说,您必须只能从主线程访问 VCL 组件。您的代码违反了该规则。
每当您想从线程访问 VCL 组件时,请使用 TThread.Synchronize
或 TThread.Queue
方法在主线程上执行代码。
看看你的代码,如果你真的想在每次触发计时器时创建一个新线程,我会感到惊讶。这真的是你打算做的吗?并且在计时器过程中使用 try/finally
充其量是可疑的。如果引发异常,你真的想启动线程吗?编译器应该告诉您 Resume
方法已被弃用,您应该改用 Start
。您是否启用了编译器提示和警告?您几乎肯定不希望修改线程优先级。如果使用不当,可能会导致各种问题,就像这里的情况一样。
综上所述,如果您愿意并避免使用任何线程,您可以使用计时器完美地编写代码。您需要声明几个计数器,每次定时器过程触发时它们都会递增。例如:
type
TForm1 = class(TForm)
....
private
FCounter1: Integer;
....
end;
然后当你想开始计数时,你初始化计数器并启动计时器:
FCounter1 := 0;
Timer1.Enabled := True;
每当计时器触发您的增量计数器时。当计数器达到上限值时停止计数器。
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Memo1.Lines.Add(IntToStr(FCounter1));
inc(FCounter1);
if FCounter1 > 50 then
Timer1.Enabled := False;
end;
您的代码,已更正为仅在主线程中执行 UI 操作。它对我有用:
TThread_Timer2 = class(TThread)
private
FVar: Integer;
procedure UpdateMemo;
protected
procedure Execute; override;
end;
TThread_Timer3 = class(TThread)
private
FVar: Integer;
procedure UpdateMemo;
protected
procedure Execute; override;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
var
thd : TThread_Timer2;
begin
thd := TThread_Timer2.Create(true);
try
thd.FreeOnTerminate := true;
thd.Priority := tpHighest;
finally
thd.Resume;
end;
end;
procedure TThread_Timer2.Execute;
var
i : integer;
begin
for i := 0 to 50 do
begin
FVar := i;
Synchronize(UpdateMemo);
sleep(500);
end;
end;
procedure TThread_Timer3.Execute;
var
k : integer;
begin
for k := 0 to 50 do
begin
FVar := k;
Synchronize(UpdateMemo);
sleep(500);
end;
end;
procedure TForm1.Timer2Timer(Sender: TObject);
var
trhd : TThread_Timer3;
begin
trhd := TThread_Timer3.Create(true);
try
trhd.FreeOnTerminate := true;
trhd.Priority := tpHighest;
finally
trhd.Resume;
end;
end;
procedure TThread_Timer2.UpdateMemo;
begin
Form1.Memo1.Lines.Add(IntToStr(FVar));
end;
procedure TThread_Timer3.UpdateMemo;
begin
Form1.Memo2.Lines.Add(IntToStr(FVar));
end;
我没有更改您代码中的任何其他内容,但请仔细阅读 David 的回答。里面有备注要注意
亚当,
如果使用 Parallel 库会更容易。您的初始程序将是这样的:
proceedure TForm1.Timer1Timer(Sender: TObject);`
begin
TTask.Run(procedure
var
i: integer;
begin
for i:=0 to 50 do
begin
TThread.Synchronize(TThread.CurrentThread,
procedure
begin
Memo1.Lines.Add(i.ToString);
Sleep(500);
end);
end;
end);
end;
根据@GabrielF的回复,我添加了一个ttimer,并做了一个完整的代码复制过去:
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
procedure Timer1Timer(Sender: TObject);
procedure Timer2Timer(Sender: TObject);
public
{ Public declarations }
end;
TThread_Timer2 = class(TThread)
private
FVar: Integer;
procedure UpdateMemo;
protected
procedure Execute; override;
end;
TThread_Timer3 = class(TThread)
private
FVar: Integer;
procedure UpdateMemo;
protected
procedure Execute; override;
end;
var
Form1: TForm1;
Memo1:TMemo;
Memo2:TMemo;
Timer: TTimer;
implementation
{$R *.dfm}
procedure TForm1.Timer1Timer(Sender: TObject);
var
thd : TThread_Timer2;
begin
thd := TThread_Timer2.Create(true);
try
thd.FreeOnTerminate := true;
thd.Priority := tpHighest;
finally
thd.Resume;
end;
end;
procedure TThread_Timer2.Execute;
var
i : integer;
begin
for i := 0 to 10 do
begin
FVar := i;
Synchronize(UpdateMemo);
sleep(1000);
end;
end;
procedure TThread_Timer3.Execute;
var
k : integer;
begin
for k := 0 to 10 do
begin
FVar := k;
Synchronize(UpdateMemo);
sleep(1000);
end;
end;
procedure TForm1.Timer2Timer(Sender: TObject);
var
trhd : TThread_Timer3;
begin
trhd := TThread_Timer3.Create(true);
try
trhd.FreeOnTerminate := true;
trhd.Priority := tpHighest;
finally
trhd.Resume;
end;
end;
procedure TThread_Timer2.UpdateMemo;
begin
Memo1.Lines.Add(IntToStr(FVar));
end;
procedure TThread_Timer3.UpdateMemo;
begin
Memo2.Lines.Add(IntToStr(FVar));
end;
procedure TForm1.FormCreate(Sender: TObject);
var bt1,bt2: TButton;
begin
Form1.Width:=440;
Form1.Height:=500;
//
Memo1 := TMemo.Create(nil);
Memo1.Width := 200;
Memo1.Height := 400;
Memo1.Top := 30;
Memo1.Parent := Form1;
//
Memo2 := TMemo.Create(nil);
Memo2.Width := 200;
Memo2.Height := 400;
Memo2.Top := 30;
Memo2.Left := 210;
Memo2.Parent := Form1;
//
Timer := TTimer.Create(nil);
Timer.Interval := 10000;
Timer.OnTimer := Timer2Timer;
Timer.Enabled := true;
//
bt1 := TButton.Create(nil);
bt1.Width := 200;
bt1.OnClick := Timer1Timer;
bt1.Caption := 'Create thread Memo1';
bt1.Parent := Form1;
//
bt2 := TButton.Create(nil);
bt2.Left:=210;
bt2.Width := 200;
bt2.OnClick := Timer2Timer;
bt2.Caption := 'Create thread Memo2';
bt2.Parent := Form1;
end;
end.
也许它对某人有帮助。我是在Delphi7上写测试的。