6
votes

Pourquoi les threads fonctionnent-ils en série dans cette application de console?

Je crée une application de console qui doit exécuter plusieurs threads afin d'accomplir une tâche. Mon problème est que les threads sont en cours d'exécution l'un après l'autre (Thread1 Démarrer -> Travail -> Fin et seulement Démarrer le thread2) au lieu de courir tout en même temps. De plus, je ne veux pas que plus de 10 threads travaillent dans le même temps (problèmes de performance). BOWER est un exemple de code d'application de la console et du DataModule utilisé. Ma candidature fonctionne de la même manière. J'ai utilisé un DataModule car une fois les threads terminés, je dois remplir une base de données avec ces informations. Il existe également des commentaires dans le code d'explication qui est la raison de faire quelque chose.

Code de la console de l'application: xxx

et code de données xxx

donc, comme je l'ai dit le problème que mes fils fonctionnent l'un après l'autre, au lieu de travailler tout en même temps. Aussi, j'ai vu que, parfois, le premier fil a fonctionné, après que tout le reste ne soit que créé et fini. Dans mon application, tout le code est protégé par TRY-SAUFS, mais aucune erreur n'est soulevée.

Quelqu'un peut-il me donner un conseil?


3 commentaires

Un bon moyen de s'assurer que plus de 10 threads courent immédiatement pour utiliser un Semaphore . Acquérez-le avant de créer un thread et que chaque fil est libéré lors de la résiliation. S'il y a déjà 10 threads en cours d'exécution, la onzième tentative d'acquisition du sémaphore bloquera jusqu'à ce qu'un autre fil se termine. Ensuite, vous n'avez pas besoin de ces processus de processage. Ces boucles ne font que manger du temps de processeur parce que votre application n'a jamais envoie tous les messages, il n'y aura jamais rien à traiter.


Une autre étape que vous pouvez prendre est de n'appeler que checksynchroniser quand il y a en fait quelque chose à synchroniser avec. Avec votre sémaphore configuré, appelez MSGWAITECOMULTIPLEObjects sur la poignée SEMAPHORE et la variable globale Synceventer . Lisez à ce sujet dans les classes.pas. Si le sémaphore est signalé, créez un nouveau fil. Si l'événement est signalé, appelez CheckSynchroniser.


Rob, merci beaucoup pour les informations. J'ai lu maintenant sur les sémaphores, mais je ne suis pas sûr de bien comprendre comment dois-je le mettre en œuvre. D'après ce que j'ai lu, j'ai besoin d'utiliser WaitforSingleObject (poignée, infinie) - pour le fil de finition pour terminer tout le cycle, mais comment puis-je savoir quand commencer un autre fil? J'ai vu des exemples alors je crois que je dois créer un sémaphore avec 10 threads, mais lorsque je crée comment je crée un nouveau fil et le déjeuner dans Semaphore? Quelqu'un peut-il me fournir un petit exemple basé sur mon exemple? Merci d'avance!


3 Réponses :


7
votes

à tout le moins que vous devriez mettre xxx

à l'extérieur de la boucle principale. Cette boucle d'attente est ce qui cause la maintien. Pour chaque entier I du Mainloop, il attend que la FtheadCount tombe à zéro.

sur un Sidenote: Normalement, vous n'avez pas besoin de protéger les variables locales avec des sections critiques. Bien que les messages de traitement dedans, il puisse subir des objets, car il peut provoquer une réintensif.


0 commentaires

-1
votes

J'ai une unité qui fait exactement ce dont vous avez besoin. Il suffit de le télécharger à partir de:

Cromis.threading

à l'intérieur, vous avez deux classes:

  1. Ttaskpool: Piscine de tâches. Manière facile de faire des choses asynchrones.
  2. TtaskQueue: une file d'attente de tâches asynchrones. Fonctionne comme une file d'attente FIFO standard.

    Le TtaSkQueue peut être utilisé autonome avec des filets de Vanila simples par exemple. Il bloque à l'intérieur d'un seul fil et files d'attente les demandes.

    Si cela ne suffit pas, vous pouvez vérifier l'omnithreadlibrary à:

    omnithreadlibrary

    Ceci est une puissant bibliothèque de filetage, de loin supérieure à ce que j'ai. Mais aussi plus compliqué à utiliser (mais toujours très facile par rapport au filetage classique).


1 commentaires

Je ne pense pas qu'il veuille que les fils s'enoncent l'un après l'autre. Il n'est pas sûr de savoir pourquoi ils ne fonctionnent pas en parallèle.



1
votes

J'ai suivi la suggestion de Marjan et le code suivant semble fonctionner correctement. Je réponds à ma propre question afin de fournir un code de réponse, qui peut être analysé par d'autres personnes et corrigé si nécessaire.

unit Unit1;

interface

uses
  SysUtils, Classes, SyncObjs, Windows, Forms, Dialogs;

var   FCritical: TRTLCriticalSection;  

type
  TTestThread = class(TThread)
  protected
    procedure Execute;override;
  end;
  TDataModule1 = class(TDataModule)
    procedure DataModuleCreate(Sender: TObject);
    procedure DataModuleDestroy(Sender: TObject);
  private
    { Déclarations privées }
  public

    procedure execute;
    procedure CreateThread();
    procedure Onterminatethrd(Sender: TObject);
  end;

var
  DataModule1       : TDataModule1;
  FthreadCount      : Integer;


implementation

{$R *.dfm}

{ TTestThread }

procedure TTestThread.Execute;
var
  f                 : TextFile;
  i                 : integer;

begin
 AssignFile(f, 'd:\a\a' + inttostr(FthreadCount) + '.txt');
 if fileexists('d:\a\a' + inttostr(FthreadCount) + '.txt') then
  Append(f)
 else
  Rewrite(f);
   try
    i := 0;
    while i <= 1000000 do
      Inc(i);
  Writeln(f, 'done '+floattostr(self.Handle));
  finally
    CloseFile(f);
  end;
end;

{ TDataModule1 }

procedure TDataModule1.CreateThread;
var
  aThrd             : TTestThread;
begin
  aThrd := TTestThread.Create(True);
  aThrd.FreeOnTerminate := True;
  EnterCriticalSection(fcritical);
  Inc(FthreadCount);
  LeaveCriticalSection(fcritical);
  aThrd.OnTerminate:=Onterminatethrd;
  try
    aThrd.Resume;
  except
    FreeAndNil(aThrd);
  end;
end;

procedure TDataModule1.Onterminatethrd(Sender: TObject);
begin
  EnterCriticalSection(fcritical);
    Dec(FthreadCount);
  LeaveCriticalSection(fcritical);
end;

procedure TDataModule1.DataModuleCreate(Sender: TObject);
begin
  InitializeCriticalSection(fcritical);
end;

procedure TDataModule1.DataModuleDestroy(Sender: TObject);
begin
  DeleteCriticalSection(fcritical);
end;

procedure TDataModule1.execute;
var
  i                 : integer;
begin
  i := 0;
 try
  while i < 1000 do
  begin
    while (FthreadCount = 10) do
     begin
      Application.ProcessMessages;
      CheckSynchronize
     end;
    CreateThread;
    Inc(i);
  end;
    while FthreadCount > 0 do
    begin
      Application.ProcessMessages;
      CheckSynchronize;
    end;
 except on e:Exception do
//
 end;
end;

end.


1 commentaires

Il existe un article et un exemple sur la mise en œuvre de sémaphores avec Delphi ici: edn.embarcadero.com/article/29908