1

我这里有一些代码:

procedure TForm1.Button1Click(Sender: TObject);
begin
  //Some Codes(1)
  Sample;
  //Some Codes(2)
end;

Function Sample();
begin
  sleep(5000);
end;

在这段代码中,//Somecodes(1)应用程序Sample运行并等待 5 秒后,它运行//Somecodes(2)对吗?这意味着要解冻Button1,我们必须等待超过 5 秒。

现在我想做一些事情,当应用程序运行时//Some Codes(1)Sample立即转到下一行(//Somecodes(2)),所以我不需要等待 5 秒来按钮 1 Unfreez。

我该怎么做?

4

1 回答 1

9

就像 Andreas 所说,您可以为此使用线程。您可以将它们与这样的匿名过程一起使用:(注意:TThread.CreateAnonymousThread 在 Delphi 2010 中似乎还不存在。我在下面解决这个问题。)

procedure TForm1.Button1Click(Sender: TObject);
begin
  TThread.CreateAnonymousThread(
    procedure
    begin
      // Chunk of code 1
      Sleep(5000);
      MessageBox(0, 'x', 'x', MB_OK);
    end).Start;

  TThread.CreateAnonymousThread(
    procedure
    begin
      // Chunk of code 2
      Sleep(5000);
      MessageBox(0, 'y', 'y', MB_OK);
    end).Start;
end;

您也可以实现自己的线程类,但使用 CreateAnonymousThread 您可以只传递在线程中执行的过程。您可以调用 Start(或 Run)来立即运行线程,使用 CreateAnonymousThread 创建的线程在完成后会自行释放。

因此,这两个代码块将同时运行。这意味着 5 秒后,您将获得两个紧挨着的弹出窗口(您可以将最上面的窗口拖到一边以查看另一个)。此外,该按钮将在单击后直接响应,而睡眠在后台运行。

请注意,尽管大多数 VCL 不是线程安全的,因此您应该注意不要修改这些线程中的(可视)组件。

关于线程安全

就像评论中提到的 J... 一样,不仅仅是 VCL 不是线程安全的。许多代码不是,您自己的代码也需要注意这一点。例如,如果我稍微修改上面的代码,我可以让两个线程计数到十亿并增加一个共享整数。您预计到线程完成时整数将达到 20 亿,但在我的测试中,它达到了刚刚超过 10 亿。那是因为两个线程同时更新同一个整数,覆盖了另一个线程的尝试。

procedure TForm6.FormCreate(Sender: TObject);
var
  n: Integer;
begin
  n := 0;
  TThread.CreateAnonymousThread(
    procedure
    var i: Integer;
    begin
      for i := 0 to 1000000000 do
        Inc(n);
      MessageBox(0, 'x', 'x', MB_OK);
    end).Start;

  TThread.CreateAnonymousThread(
    procedure
    var i: Integer;
    begin
      for i := 0 to 1000000000 do
        Inc(n);
      MessageBox(0, 'y', 'y', MB_OK);
    end).Start;

  Sleep(10000); // Make sure this is long enough. The number should appear later than 'x' and 'y'.
  ShowMessage(IntToStr(n));
end;

要解决此问题,您可以同步更新(在主线程中执行),或使用临界区锁定更新。如果您实际上只是以整数更新,您也可以使用该InterlockedIncrement函数。我不会进一步解释这些,因为有很多适当的文档,它超出了这个答案的范围。

但请注意,这些方法中的每一个都会通过一个接一个地执行代码片段而不是同时执行来减慢您的应用程序的速度。您正在有效地使线程相互等待。尽管如此,线程仍然有用,如果您可以微调它们以便只需要同步小部分。

Delphi 2010 中的 TThread.CreateAnonymousThread

TThread.CreateAnonymousThread 只是创建 TAnonymousThread 的一个实例,这是一个执行给定过程的特定线程类。

由于 Delphi 2010 中不存在 TThread.CreateAnonymousThread,因此您可以这样调用它:

  TAnonymousThread.Create(
    procedure
    var i: Integer;
    begin
      for i := 0 to 1000000000 do
        Inc(n);
      MessageBox(0, 'x', 'x', MB_OK);
    end).Start;

我不知道 TAnonymousThread 本身是否存在于 Delphi 2010 中,但如果不存在,您可以在下面找到它的代码。我希望 Embarcadero 不介意我分享它,但它实际上只是四行简单的代码。

这个类你可以很容易地自己创建,但它的声明如下。构造函数采用单个参数,即要执行的过程。它还设置了一个属性,使线程在完成后自行释放。该execute方法只执行给定的过程。

type
  TAnonymousThread = class(TThread)
  private
    FProc: TProc;
  protected
    procedure Execute; override;
  public
    constructor Create(const AProc: TProc);
  end;

constructor TAnonymousThread.Create(const AProc: TProc);
begin
  inherited Create(True);
  FreeOnTerminate := True;
  FProc := AProc;
end;

procedure TAnonymousThread.Execute;
begin
  FProc();
end;
于 2013-07-16T19:25:35.563 回答