我如何在delphi项目中执行两个线程

时间:2016-03-16 15:10:48

标签: multithreading delphi delphi-xe7

我的项目包含两个执行不同任务的过程, 我执行计时器中的每个线程。

我的问题是,当我运行项目时,计时器启动。 线程不能正常工作。

为什么吗

并且,我可以在同一个项目中使用两个或更多线程吗?

注意:我真的想使用线程,我需要一个带线程的解决方案。

这是我没有线程的代码。

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;

4 个答案:

答案 0 :(得分:8)

您可以根据需要使用尽可能多的线程。但是你必须遵守VCL的规则。具体而言,您只能从主线程访问VCL组件。您的代码违反了该规则。

每当您想从线程访问VCL组件时,请使用TThread.SynchronizeTThread.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;

答案 1 :(得分:3)

您的代码,通过更正仅在主线程中执行UI操作。它为我工作:

--color
--require spec_helper
--format documentation

我没有更改代码中的任何其他内容,但对David的回答有一个很好的解读。你应该注意那里的评论。

答案 2 :(得分:0)

亚当,

如果使用Parallel库会更容易。你的初始程序是这样的:

@ECHO Off
SETLOCAL
SET "result=12.2.4.194"
ECHO %RESULT%
CALL :CONVERT results %result%
ECHO %results%

CALL :CONVERT resultv 12.2.4.194

ECHO compare %result% to 12.2.4.194

IF /I %RESULTs% GTR %resultv% ECHO(GOTO NEWERVERSION
IF /I %RESULTs% EQU %resultv% ECHO(GOTO CORRECTVERSION
IF /I %RESULTs% LSS %resultv% ECHO(GOTO OUTDATEDVERSION


CALL :CONVERT resultv 1.2.4.194

ECHO compare %result% to 1.2.4.194

IF /I %RESULTs% GTR %resultv% ECHO(GOTO NEWERVERSION
IF /I %RESULTs% EQU %resultv% ECHO(GOTO CORRECTVERSION
IF /I %RESULTs% LSS %resultv% ECHO(GOTO OUTDATEDVERSION

CALL :CONVERT resultv 12.10.4.194

ECHO compare %result% to 12.10.4.194

IF /I %RESULTs% GTR %resultv% ECHO(GOTO NEWERVERSION
IF /I %RESULTs% EQU %resultv% ECHO(GOTO CORRECTVERSION
IF /I %RESULTs% LSS %resultv% ECHO(GOTO OUTDATEDVERSION

GOTO :EOF

:CONVERT
SETLOCAL 
FOR /f "tokens=1-4delims=." %%a IN ("%2") DO (
 SET /a resulta=1000+%%a
 SET /a resultb=1000+%%b
 SET /a resultc=1000+%%c
 SET /a resultd=1000+%%d
)
endlocal&SET "%1=v%resulta%.%resultb%.%resultc%.%resultd%"
GOTO :eof

答案 3 :(得分:0)

根据@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上编写并测试了它。