【问题标题】:Simple Thread Sample Delphi简单的线程示例 Delphi
【发布时间】:2011-03-27 22:33:32
【问题描述】:

我对 Delphi 中的线程处理这个东西很陌生。所以,我正在尝试制作一个简单的查询应用程序,它会调用数据库并花费一些时间,所以我想提醒用户有一个后台进程并且必须耐心等待。

我尝试了很多示例,但没有一个对我有用,请问有人可以给我看一个可以工作的简单示例吗?

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

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

谢谢。

【问题讨论】:

  • 您尝试了很多样本​​,但都失败了。那么什么会给你另一个例子呢?你应该问更详细的问题。你有什么问题?顺便说一句,这个教程看起来不错:wiki.lazarus.freepascal.org/Multithreaded_Application_Tutorial
  • 还有一个更好的解决方案(因为它更简单)只是在耗时的过程中不时调用 Application.ProcessMessages (例如,只是为了更新一些进度条或播放一些其他动画向用户显示应用程序正忙)。
  • 这是我发现有用的示例:Multi-Threading Delphi Database Queries
  • 嗨,adf88,我完全同意你的看法。但是样本的问题是我真的不了解 Thread 的全部内容,所以我认为一个简单的样本可以让我更清楚地了解这些事情。无论如何,我用 Application.Processmessages 解决了这个问题,谢谢

标签: multithreading delphi


【解决方案1】:

是的,你声明了一个继承自 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,如果线程还没有结束,它就立即存在。

【讨论】:

  • 我知道这只是示例代码,但是如果用户多次单击按钮会发生什么情况的注释会很有用。
  • 最新代码块定义中的“TThread”不应该是“MyWorkerThread: TMyWorkerThread”吗?
  • @ThatMarc:这里的想法是你不需要知道 TMyWorkerThread 做了什么特定的工作来知道线程已经结束。任何 TThread 后代都可以这样检查。
  • 感谢您的信息。我并不想在这里变得聪明,而是第一次处理线程,只是想确保我正确理解了...... :) 感谢 bdw 的精彩帖子!有助于更好地理解线程...
  • 顺便说一句,有没有其他不依赖Windows函数WaitForSingleObject的方法,也可以针对其他平台?
【解决方案2】:

您可以在线程网络上找到许多示例。如果您在 Thread 中使用 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 方法,该方法在线程完成时接收线程控制。与其他线程唯一不同的是连接问题。您必须在每个线程上创建一个新连接,它不能与其他线程共享相同的 ADOConnection。
我希望这个例子对你有用。

问候

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-17
    • 1970-01-01
    • 2012-01-11
    • 2013-04-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多