简单的线程示例Delphi

时间:2010-08-10 16:22:36

标签: multithreading delphi

我是熟悉Delphi中线程的新手。所以,我正在尝试创建一个简单的查询应用程序,为数据库调用一点并花一点时间,所以我想提醒用户有一个后台进程,并且必须耐心等待。

我尝试过很多样本,但是没有一个样本适合我,拜托,有人可以给我看一个可行的简单样本吗?

我知道我必须声明一种类型的TThread,使用Create和Override Execute ......等等。但是因为我失去了......

使用Delphi 7,SQL Server 2005和ADO,Windows XP sp3 .-

感谢。

2 个答案:

答案 0 :(得分:52)

是的,你声明了一个继承自TThread的新类型:

TMyWorkerThread = class(TThread)
end;

然后为Execute()添加函数覆盖:

TMyWorkerThread = class(TThread)
public
  procedure Execute; override;
end;

启动线程时将调用该过程。它将与您的主程序并行执行。我们来写吧。

procedure TMyWorkerThread.Execute;
begin
  //Here we do work
   DoSomeWork();
   DoMoreWork();
  //When we exit the procedure, the thread ends.
  //So we don't exit until we're done.
end;

如何使用这个?假设您想在用户单击按钮时开始工作。您编写了一个OnClick处理程序:

procedure TMainForm.Button1Click(Sender: TObject);
begin
  TMyWorkerThread.Create(false);
end;

就是这样。用户单击按钮后,您的线程将启动并继续执行您在Execute中编写的任何内容。如果用户再次单击该按钮,则另一个线程将启动,然后另一个线程 - 每次单击一个。它们都将并行运行,每个都执行在Execute()中写入的所有内容,然后结束。

假设您要检查工作是否结束。为此,您必须将引用存储在某个地方:

TMainForm = class(TForm)
{...skipped...}
public
  MyWorkerThread: TThread;
end;

procedure TMainForm.Button1Click(Sender: TObject);
begin
  //This time we make sure only one thread can be started.
  //If one thread have been started already, we don't start another.
  if MyWorkerThread<>nil then
    raise Exception.Create('One thread have already been started!');
  MyWorkerThread := TMyWorkerThread.Create(false);
end;

procedure TMainForm.Button2Click(Sender: TObject);
begin
  //If the work is not over yet, we display message informing the user we're still working
  if (MyWorkerThread<>nil) and (WaitForSingleObject(MyWorkerThread.Handle, 0)<>WAIT_OBJECT_0) then
    MessageBox(Self.Handle, pchar("The work is not yet done!"), pchar("Still running"), MB_OK);
end;

如您所见,我们通过调用名为WaitForSingleObject的Windows函数来检查线程是否仍在运行。此函数等待线程完成工作,或超时已过,并且当我们指定超时为0时,如果线程尚未结束,它将立即存在。

答案 1 :(得分:32)

您可以在线程网上找到许多示例。如果您在线程内部使用ADO连接,唯一的特殊功能是您不能共享相同的连接 每个线程必须创建自己的连接,否则它们是相同的(应该遵循与任何其他线程相同的规则。)

我使用的样本是:

  TADOSQLThread = class(TThread)
  private
    FADOQ: TADOQuery;  // Internal query
    FSQL: string;      // SQL To execute
    FID: integer;      // Internal ID

  public
    constructor Create(CreateSuspended:Boolean; AConnString:String;
                       ASQL:string; IDThread:integer);
    destructor Destroy; override;
    procedure Execute(); override;

    property ID:integer read FID write FID;
    property SQL:string read FSQL write FSQL;
    property ADOQ:TADOQuery read FADOQ write FADOQ;
  end;

Create构造函数被覆盖,如下所示:

constructor TADOSQLThread.Create(CreateSuspended:Boolean; AConnString:String;
                                 ASQL:string; IDThread:integer);
begin

  inherited Create(CreateSuspended);

  // ini
  Self.FreeOnTerminate := False;

  // Create the Query
  FADOQ := TAdoquery.Create(nil);
  // assign connections
  FADOQ.ConnectionString := AConnString;
  FADOQ.SQL.Add(ASQL);
  Self.FID := IDThread;
  Self.FSQL:= ASQL;
end;

执行方法非常简单:

procedure TADOSQLThread.Execute();
begin

  inherited;

  try
    // Ejecutar la consulta
    Self.FADOQ.Open;
  except
    // Error al ejecutar
    ...Error treattement
  end;
end;

要启动并创建一个线程,您可以使用与此类似的代码:

  //crear el Thread
  th := TADOSQLThread.Create(True, mmConnection.Lines.Text, ASQL, AId);
  // internal for me (for controled the number of active threads and limete it)
  inc(numThreads);
  // evento finalizacion
  th.OnTerminate := TerminateThread;
  // Ejecutarlo
  th.Resume;

我创建了一个 TerminateThread 方法,在完成后接收线程控制。与其他线程唯一不同的是连接问题。您必须在每个线程上创建一个新连接,它不能与其他线程共享相同的ADOConnections 我希望这个例子对你有用。

此致