Thread : Synchronize Bloqué !!!! [Résolu]

picolo5 31 Messages postés lundi 9 août 2004Date d'inscription 18 décembre 2006 Dernière intervention - 10 août 2006 à 15:53 - Dernière réponse : picolo5 31 Messages postés lundi 9 août 2004Date d'inscription 18 décembre 2006 Dernière intervention
- 31 août 2006 à 13:52
Bonjour à tous !

Je dev un projet qui utlise une dll. Cette dll me permet de me connecter à un serveur et de recuperer une trame.

J ai donc mis en place un thread pour executer l "ecoute" du serveur :

----------------------------------------------------------------------------------------------------------------------------------
unit Unit2;


interface


uses
  Classes,Windows,Unit1 ;




type
  MonThread = class(TThread)
  private
    FForm : TForm1;
    { Déclarations privées }
  protected
    procedure Execute; override;
    procedure Traiter;
    procedure Sync;
    public
    constructor Create(Form : TForm1);


  end;


implementation


{ Function importées de la DLL}
function OpenSession(loggin : PChar; pswd : PChar): integer; StdCall; external 'Test.dll';
function Init(portServSPAD : integer ;portServTPAD : integer): integer; StdCall; external 'Test.dll';
function CloseSession(): integer; StdCall; external 'Test.dll';
function GetMessage(messages : PChar): integer; StdCall; external 'Test.dll';


 


{ MonThread }


var
    trame : array[0..1024] of char;
    LaTrame : string;


procedure MonThread.Traiter;
begin
   FForm.Ed_Loggin.Text := 'Grrrrrrrr';
   FForm.TraiterTrame(Trame);
end;




constructor MonThread.Create(Form: TForm1);
  begin
    inherited Create(False);
    FForm := Form;
    FreeOnTerminate := True;
  end;


procedure MonThread.Sync();
begin
Synchronize(Traiter);
End;


procedure MonThread.Execute;
var
  test : boolean;
  ret : integer;
  SPass,SLoggin : string;
begin
  while not Terminated do
    begin
    sleep(1500);
    ret := GetMessage(trame);


    if ret <> 0 then
      begin
      // Gerer la reconnection
      Init(3002,3001);
      CloseSession();
      Sleep(5);
      SPass := 'EMULOP01';
      SLoggin := 'EMULOP01';
      OpenSession(PChar(SPass),PChar(SLoggin));
      end
    else
      begin
      LaTrame := String(trame);
      if LaTrame <> '' then
      }
      Sync();
      //Form1.TraiterTrame(String(Trame));  // Je triche en virant les // et en desactivant Sync(),  ca marche mais ce n est
                                                                 //     pas  'securisé'
      end;
    end;
end;


end.
----------------------------------------------------------------------------------------------------------------------------------

Je lance mon app (une form avec un bouton pour lancer le thread, la procedure TForm1.TraiterTrame(Trame))

puis je click sur le bouton de lancement du thread :

MyThread:= MonThread.Create(Form1);

Le thread se lance, fait son travail et :

-Si ma souris est sur la form, le synchronize du thread se fait correctement !
-Si ma souris est hors de la form, le thread ne rentre pas ds la procedure à synchronize tant que je ne rentre pas ma souris sur la form. (si je met un point d arret à l entree de Traiter() il n est atteind que ds le cas ou ma souris reviens sur la form !!)

J ai ajouté le passage de la form a mon thread en pensant que le prob venait de la.... mais non :(
J ai essayer de virer tout le code 'superflu' de la methode execute en ne laissant que le synchronize, mais c est idem.

Si je supprime le Sync() et que je le remplace par : Form1.TraiterTrame(String(Trame)); 
cela marche correctement, mais n est pas 'Sécurisé' ??

Au secours !!!!!

Merci ;)
Afficher la suite 

Votre réponse

6 réponses

Meilleure réponse
cs_Delphiprog 4580 Messages postés samedi 19 janvier 2002Date d'inscription 9 janvier 2013 Dernière intervention - 10 août 2006 à 23:35
3
Merci
Salut à tous, amis des threads

A priori, en épurant ton code et en restructurant, voici le code qui fonctionne et qui est aussi proche possible de ce que tu nous décris.
Avant tout, pour éviter les références croisées entre l'unité de la fiche et celle du thread, j'ai ajouté une troisième unité nommée...Unit3 :

unit Unit3;

interface

type
  TTrame =   array [0..1024] of char;

implementation

end.

Ce qui permettra l'utilisation d'un type commun entre la méthode TraiterTrame de la fiche et le membre de la classe TMonThread (noter l'ajout du 'T' pour respecter les conventions standards).
Voici un extrait du code de la fiche, contenu dans Unit1_1.pas :
var
  MonThread: TMonThread  = nil;

{ TForm1 }

procedure TForm1.TraiterTrame(Trame: TTrame);
begin
  Label1.Caption :=  Trame;
 end ;

procedure TForm1.Button1Click(Sender: TObject);
begin
  //pas plus d'1 thread à la fois svp
  if MonThread  = nilthen
    MonThread :=  TMonthread.Create(Self);
 end ;

procedure TForm1.Button2Click(Sender: TObject);
begin
  if MonThread <> nilthen
    MonThread.Terminate;
  MonThread : = nil;
end;

Puis, le meilleur pour la fin :

unit Unit2;

interface

uses
  Classes, Windows, Unit1_1, Unit3;

type
  TMonThread =   class (TThread)
  private
    FForm: TForm1;
    Trame: TTrame;
    procedure Fin;
  protected
    procedure Execute; override;
    procedure Traiter;
    procedure WhenTerminated(Sender: TObject);
  public
    constructor Create(Form: TForm1);
  end;

implementation

uses SysUtils;

{ TMonThread }

procedure TMonThread.Traiter;
begin
  FForm.Ed_Loggin.Text : = 'Test de trame...';
  FForm.TraiterTrame(Trame);
end;

constructor TMonThread.Create(Form: TForm1);
begin
  inherited Create(False);
  FForm :=  Form;
  OnTerminate := WhenTerminated;
  FreeOnTerminate := True;
 end ;

procedure TMonThread.Execute;
var
  ret: integer;
begin
  Ret : = 0;
  //s'arrêtera automatiquement au bout de 20 secondes
  whilenot Terminated and (Ret < 20) do
  begin
    sleep(1000);
    inc(ret);
    StrPCopy(Trame, 'Envoi de la trame ' + IntToStr(Ret));
    if Trame[0] <> #0then
      Synchronize(Traiter);
  end;
end;

procedure TMonThread.WhenTerminated(Sender: TObject);
begin
  Synchronize(Fin);
end;

procedure TMonThread.Fin;
begin
  FForm.Ed_Loggin.Text :=  'Terminé !';
 end ;

end.

En dehors de l'ajout d'une méthode pour bien pouvoir observer l'arrêt du thread sur la fiche, la variable LaTrame a été avantageusement remplacée par le tableau de caractères. J'ai trouvé qu'il était inutile de dupliquer d'un PChar dans une string.

Ce code fonctionne, avec ou sans souris au dessus de la fiche, la fenêtre en arrière plan comme en avant plan mais également quand on déplace la fenêtre en cours d'exécution.
Teste le.
Si tout fonctionne aussi chez toi, c'est que ton problème vient soit de la dll, soit d'ailleurs.

May Delphi be with you !
<hr color ="#008000" />
Pensez à cliquer sur Réponse acceptée lorsque la réponse vous convient.

Merci cs_Delphiprog 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 69 internautes ce mois-ci

Commenter la réponse de cs_Delphiprog
cs_Loda 900 Messages postés vendredi 3 novembre 2000Date d'inscription 30 juillet 2009 Dernière intervention - 10 août 2006 à 16:13
0
Merci
salut,

je m'y connais pas trop en thread, mais c'est pas:

TThread.Synchronize(Sender,methode) plustot?

bon code,
Commenter la réponse de cs_Loda
picolo5 31 Messages postés lundi 9 août 2004Date d'inscription 18 décembre 2006 Dernière intervention - 10 août 2006 à 16:45
0
Merci
Il me semble bien que j utilise la bonne declaration de Synchronize, je ne trouve nulle part de version TThread.Synchronize(Sender,methode) uniquement TThread.Synchronize(methode)
Commenter la réponse de picolo5
cs_Forman 663 Messages postés samedi 8 juin 2002Date d'inscription 6 avril 2010 Dernière intervention - 10 août 2006 à 20:22
0
Merci
Salut,

Peut-être que le problème vient de la façon dont tu lances le thread. Le code que tu as posté me parait tout à fait valide, mais il faudrait que tu postes aussi le source de la form pour voir s'il n'y a pas un problème là (par exemple si tu lances le thread dans un événement, et que tu fais un WaitFor dans l'événement).
Commenter la réponse de cs_Forman
cs_Forman 663 Messages postés samedi 8 juin 2002Date d'inscription 6 avril 2010 Dernière intervention - 10 août 2006 à 20:33
0
Merci
Après avoir relu la façon dont Borland a implémenté la méthode Synchronize, j'ai lu que lorsque l'application entre dans un état IDLE (en attente de messages), elle crée une procédure WakeMainThread qui fait ceci:

procedure TApplication.WakeMainThread(Sender: TObject);
begin
PostMessage(Handle, WM_NULL, 0, 0);
end;

Cette procédure est appelée (si assignée, donc si l'application est en mode idle) par tout thread souhaitant se synchroniser. Je me souviens avoir rencontré un problème semblable sous windows millenium: l'événement OnIdle de l'application n'était pas appelé correctement. Tu as quelle version de Windows?

Sinon, le problème peut venir de ta DLL. Que se passe-t-il lorsque tu remplaces les fonctions importées par des fonctions bidons et que tu ne charges pas la DLL?
Commenter la réponse de cs_Forman
picolo5 31 Messages postés lundi 9 août 2004Date d'inscription 18 décembre 2006 Dernière intervention - 31 août 2006 à 13:52
0
Merci
Merci pour toutes ces reponses, je me remet sur ce projet aujourd'hui, je pense que ce post n'est pas encore terminé ! ;)
Commenter la réponse de picolo5

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.