web-dev-qa-db-fra.com

Exemple de thread simple Delphi

Je suis nouveau avec ce truc de Threading dans Delphi. donc, j'essaie de faire une simple application de requête qui appelle un peu la base de données et prend un peu de temps, donc je veux alerter l'utilisateur qu'il y a un processus d'arrière-plan et que je dois être patient.

J'ai essayé de nombreux échantillons, mais aucun d'entre eux ne fonctionne pour moi, s'il vous plaît, quelqu'un pourrait-il me montrer un échantillon simple qui pourrait fonctionner?

Je sais que je dois déclarer un type de TThread, avec Create et Override Execute ... etc. mais depuis, je suis perdu ...

En utilisant Delphi 7, SQL Server 2005 et ADO, Windows XP sp3.-

Merci.

27
Jose M. Vilomar

Vous pouvez trouver de nombreux exemples sur le web de threads. La seule fonctionnalité spéciale, si vous utilisez des connexions ADO à l'intérieur du fil, est que vous ne pouvez pas partager la même connexion.
Chaque thread doit créer sa propre connexion, sinon ils sont égaux (doivent suivre les mêmes règles que tout autre thread.)

Un échantillon que j'ai utilisé est le suivant:

  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;

Le constructeur Create est remplacé et ressemble à ceci:

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;

Et la méthode d'exécution est très simple:

procedure TADOSQLThread.Execute();
begin

  inherited;

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

Pour démarrer et créer un thread, vous pouvez utiliser un code similaire à celui-ci:

  //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;

J'ai créé une méthode TerminateThread qui reçoit le contrôle des threads à la fin. Le seul différent des autres threads est le problème de connexion. Vous devez créer une nouvelle connexion sur chaque thread, il ne peut pas partager les mêmes ADOConnections avec d'autres.
J'espère que cet exemple vous sera utile.

Cordialement

Oui, vous déclarez un nouveau type qui hérite de TThread:

TMyWorkerThread = class(TThread)
end;

Ensuite, vous ajoutez un remplacement de fonction pour Execute ():

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

Cette procédure sera appelée lorsque vous démarrerez votre thread. Il sera exécuté en parallèle avec votre programme principal. Écrivons-le.

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;

Comment l'utiliser? Supposons que vous souhaitiez commencer à travailler lorsque l'utilisateur clique sur le bouton. Vous écrivez un gestionnaire OnClick:

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

C'est ça. Une fois que l'utilisateur clique sur le bouton, votre thread démarre et continue à faire tout ce que vous avez écrit dans Execute. Si l'utilisateur clique à nouveau sur le bouton, un autre thread démarre, puis un autre - un à chaque clic. Ils s'exécuteront tous en parallèle, chacun faisant tout ce qui est écrit dans Execute () puis se terminant.

Disons que vous voulez vérifier si le travail est terminé. Pour cela, vous devrez stocker la référence à votre fil quelque part:

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;

Comme vous le voyez, nous vérifions si un thread est toujours en cours d'exécution en appelant une fonction Windows appelée WaitForSingleObject. Cette fonction attend que le thread ait fini de fonctionner, ou que le délai soit écoulé, et comme nous spécifions le délai de 0, il existe juste immédiatement si le thread n'est pas encore terminé.

52
himself