代码之家  ›  专栏  ›  技术社区  ›  Adam

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

  •  0
  • Adam  · 技术社区  · 9 年前

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

    我的问题是…当我运行项目时,计时器开始计时。 这根线不好用。

    为什么?

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

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

    这是我的代码,没有线程。

    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 回复  |  直到 9 年前
        1
  •  8
  •   David Heffernan    9 年前

    您可以使用任意多的线程。然而,你必须遵守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;
    
        2
  •  3
  •   GabrielF Matt Brunell    9 年前

    您的代码,带有仅在主线程中执行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;
    

    我没有更改你的代码中的任何其他内容,但请仔细阅读大卫的答案。这里有一些你应该注意的备注。

        3
  •  0
  •   John Kouraklis    9 年前

    亚当,

    如果使用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;
    
        4
  •  0
  •   lynx_74    7 年前

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