IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Delphi Discussion :

Thread et message


Sujet :

Langage Delphi

  1. #21
    Membre à l'essai

    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 19
    Points : 16
    Points
    16
    Par défaut
    Est-ce que le thread peut avoir l'initiative d'envoi d'un message, ou est-ce uniquement en réponse à un message ?
    Oui le thread prend l'initiative d'envoyé des messages quand "bon lui semble".

    Pour tes messages : soit tu utilises également un PostThreadMessage (avec un ThreadID, donc), soit tu utilises un évènement pour signaler que la donnée est prête (elle est alors lue "thread arrêté").
    Hum d'accord donc quand mon composant crée mon thread je luis envoi la valeur du thread courant (récupéré avec GetCurrentThreadId je suppose) qui dans mon cas correspont au "processus de l'application".
    Ensuite mon thread envoi les message avec PostThreadMessage.
    Et Mon Composant Lit les messages avec PeekMessage de la même maniere que mon thread.
    C'est ca que tu suggère?

    Bon si c'est le cas y a un truc bizarre lol.
    Mon composant à des propriétées qui doivent être modifiés ainsi que des procedures qui "doivent répondre vite".
    Donc comment j'integre ca dans une boucle qui attend les messages?
    Et ou doit être cette boucle?

    Y a encore de quoi réfléchir lol.

    Bon sinon je me suis penché sur les évenements, je met le code relatif à ça. Mais comme tu le disai le probleme des évenements ces que lors de leur appel le thread est bloqué, encore que vu que je gere le thread avec des messages ce n'est pa bien grave

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    type
      TClientEventWithStr = procedure(IdThread:Cardinal; Str:String) of object;
      TClientEvent        = procedure(IdThread:Cardinal) of object;
     
    type
      TCustomClientThread = class(TThread)
      private
        { Déclarations privées }
        fOnError,
        fOnStateChange,
        fOnDataSended,
        fOnDataReceived   : TClientEventWithStr;
        fOnConnected,
        fOnDisconnected   : TClientEvent;
        fClient           : TSocket;
        PfClient          : PInteger;
        fAdresse          : TClientAdresse;
        fBuf              : PChar;
        MsgStr            : String;
        fSockAddrServeur  : TSockAddr;
        procedure PrSendBuf;
        procedure PrReceiveBuf;
        procedure PrConnection;
        procedure PrDeconnection;
      protected
        procedure Execute; override;
      public
        Constructor Create( Adresse : PClientAdresse;
                            Client:TSocket); overload; 
        Constructor Create( Socket:TSocket); overload;
        Destructor Destroy; override;
      end;
     
    Procedure TCustomClientThread.Execute; 
    var
       Msg : TMsg ;
       fpHandles: ^THandle;
    begin
         fpHandles:=nil;
         While (Not Terminated) Do
               Begin
               MsgWaitForMultipleObjects(0,fpHandles,FALSE,500,QS_ALLINPUT);
               While (Not Terminated) And (PeekMessage(Msg,HWND(-1),0,0,PM_REMOVE)) Do
                     If Msg.message = CLIENT_THREAD Then
                        Case Msg.wParam of
                             CONNECTION   : PrConnection;
                             DECONNECTION : PrDeconnection;
                             RECEPTION    : PrReceiveBuf;
                             ENVOIE       : Begin
                                            fBuf:=AllocMem(Length(PChar(Msg.lParam))+1);
                                            StrCopy(fBuf,PChar(Msg.lParam));
                                            PrSendBuf;
                                            End;
     
                            SET_PROC_ERROR        : @fOnError := Pointer(Msg.lParam);
                            SET_PROC_STATE        : @fOnStateChange := Pointer(Msg.lParam);
                            SET_PROC_DATASENDED   : @fOnDataSended := Pointer(Msg.lParam);
                            SET_PROC_DATARECEIVED : @fOnDataReceived := Pointer(Msg.lParam);
                            SET_PROC_CONNECTED    : @fOnConnected := Pointer(Msg.lParam);
                            SET_PROC_DISCONNECTED : @fOnDisconnected := Pointer(Msg.lParam);
                        End
                     Else Begin
                          TranslateMessage(Msg);
                          DispatchMessage(Msg);
                          End;
               End;
    End;
     
    //Bon pour la fiche c'est plus laborieux
    type
      TForm1 = class(TForm)
        Memo1: TMemo;
        TestEvent: TButton;
        procedure TestEvent(Sender: TObject);
      private
      public
        procedure threadStr(IdThread:Cardinal; Str:String);
      end;
     
    procedure TForm1.threadStr(IdThread:Cardinal; Str:String);
    begin//pour acceder au memo obligation de préciser Form1
      Form1.memo1.Lines.Append(Str);
    end;
     
    procedure TForm1.TestEvent(Sender: TObject);
    var addrProc:TClientEventWithStr;
    begin//obligation de passer par une variable
      addrProc:=threadStr;
      PostThreadMessage(ThreadID,CLIENT_THREAD,SET_PROC_STATE,Integer(@addrProc));
    end;
    Bon voila pour l'idée procédure...Qu'est ce que tu en pense?
    En tout cas merci de suivre ce topic

  2. #22
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par sioux
    Oui le thread prend l'initiative d'envoyé des messages quand "bon lui semble".
    Et m..... !!! Bon, ben t'as choisi ton cas de figure, toi ! ;-)
    C'est pas grave, on y retourne...

    Citation Envoyé par sioux
    Hum d'accord donc quand mon composant crée mon thread je luis envoi la valeur du thread courant (récupéré avec GetCurrentThreadId je suppose) qui dans mon cas correspont au "processus de l'application".
    Oui, mais si tu fais ça, tu vas bloquer ton thread principal, car ton composant réagit sur demande (=appel de méthode) ou sur évènements (=gestionnaires). Le point bloquant, c'est que le thread peut avoir l'initiative : tu te retrouves donc à devoir établir une communication entre deux entités (thead et appli) pouvant tous deux avoir l'initiative, ce qui complexifie le traitement (une relation de type maître/esclave est beaucoup plus simple à gérer).

    Citation Envoyé par sioux
    Ensuite mon thread envoi les message avec PostThreadMessage.
    Et Mon Composant Lit les messages avec PeekMessage de la même maniere que mon thread.
    C'est ca que tu suggère?
    Oui, mais il va te falloir implémenter une méthode "GetThreadMessage" dans ton composant, qui va dérouler UNE fois la boucle (=pas de "while" dedans), et renvoie un booléen indiquant si un message a été reçu ou pas. Ca donne un truc comme ça :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    Function TMonComposant.GetThreadMessage(Var Msg : TMsg) : Boolean ;
    Begin
         Result:=PeekMessage(Msg,HWND(-1),0,0,PM_REMOVE);
    End;
    Citation Envoyé par sioux
    Bon si c'est le cas y a un truc bizarre lol.
    Bizarre, non. Pénible à mettre en place, oui ! ;-)

    Citation Envoyé par sioux
    Mon composant à des propriétées qui doivent être modifiés ainsi que des procedures qui "doivent répondre vite".
    Donc comment j'integre ca dans une boucle qui attend les messages?
    Les solutions possibles sont :
    - Passer le handle du parent du composant au thread, et repasser en messages "normaux".
    - Appeller périodiquement GetThreadMessage (via un timer, par exemple),
    - Créer un autre thread dédié à la gestion des messages entre threads (ça devient hyper pénible à mettre en place, par contre),
    - Surcharger la boucle de messages de l'application (procédure WndProc).

    Citation Envoyé par sioux
    Et ou doit être cette boucle?
    Le plus simple est de créer une nouvelle fonction WndProc, qui ne va faire que deux choses :
    - Dépiler les messages de threads,
    - Appeler la précédente procédure WndProc de manière à ne pas perturber l'application.

    Citation Envoyé par sioux
    Y a encore de quoi réfléchir lol.
    Oui...

    Citation Envoyé par sioux
    Bon sinon je me suis penché sur les évenements, je met le code relatif à ça. Mais comme tu le disai le probleme des évenements ces que lors de leur appel le thread est bloqué, encore que vu que je gere le thread avec des messages ce n'est pa bien grave
    Oups, boulette... J'aurais dû préciser. Ce ne sont pas des évènements Delphi (=avec un gestionnaire), mais des évènements Windows (=type TEvent). Jettes un oeil dessus avant, histoire de te faire une idée du fonctionnement.

    Attention quand même aux gestionnaires d'évènements (qui sont en fait des callbacks, pour clarifier les choses) : d'une part, ça bloque l'appelant, c'est une évidence.
    D'autre part, même si ton gestionnaire pointe vers la méthode d'un autre objet, tu es (et tu restes !) dans le contexte d'exécution du thread : tu peux donc générer des interblocages.
    Les évènements Windows (encapsulés par TEvent sous Delphi) n'ont pas ce problème de contexte d'exécution, mais il faut soit les "attendre", soit scruter régulièrement leur état (=polling).

    Citation Envoyé par sioux
    Bon voila pour l'idée procédure...Qu'est ce que tu en pense?
    Que ça manque de sections critiques pour garantir un fonctionnement correct en multithread des callbacks ! ;-)

    Citation Envoyé par sioux
    En tout cas merci de suivre ce topic
    Bah, j'ai vu de la lumière, alors j'suis entré...
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  3. #23
    Membre à l'essai

    Profil pro
    Inscrit en
    Septembre 2003
    Messages
    19
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2003
    Messages : 19
    Points : 16
    Points
    16
    Par défaut
    La je commence à avoir peur

    • Version message

    Par contre je vien de "tomber" sur une fonction intéressante
    Dans l'aide de delphi on trouve ça
    function AllocateHWnd(Method:TWndMethod):HWND;

    Donc je pense quand intégrant ça dans mon composant ça devrait marché correctement

    • Version procedure/event

    Bein dans un 1er temps il fault que je me documente sur les sections critiques....
    Pour améliorer le code plus haut.

    Sinon avec les TEvent je suppose que l'idée ces que le thread "active" le TEvent du composant, en lieu et place de PostThreadMessage.
    Et que le composant Test l'état des TEvent régulierement.
    Mais la quand j'ai des parametres a passer ça coince

    Bref fault que je cogite la dessus....

  4. #24
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par sioux
    Par contre je vien de "tomber" sur une fonction intéressante
    Dans l'aide de delphi on trouve ça
    function AllocateHWnd(Method:TWndMethod):HWND;
    Oui, tu peux aussi créer un window invisible pour gérer ça, en faisant gaffe à bien sauvegarder (et surtout détruire à la fin du programme) le window alloué ainsi. Mais ça revient plus ou moins à créer un thread spécialisé pour la réception Thread->Composant, en terme de complexité.

    Citation Envoyé par sioux
    Donc je pense quand intégrant ça dans mon composant ça devrait marché correctement
    Ca devrait, mais appelles-le bien au sein de ton composant, et non pas au sein de l'application. Bref, "enterres"-le au fond de ton composant, comme le thread.

    Citation Envoyé par sioux
    Bein dans un 1er temps il fault que je me documente sur les sections critiques....
    Pour améliorer le code plus haut.
    Pas de multithread sans sections critiques, c'est même pas négociable ! ;-)
    Dans ton cas, tu peux te contenter des TCriticalSection, mais jette aussi un oeil sur TMultiReadExclusiveWriteSynchronizer (je sais, le nom est horrible...), qui mérite souvent le détour lorsque beaucoup de threads "lisent" la même donnée (c'est thread-safe), et que de temps en temps, l'un d'entre eux la modifie (=pas thread-safe).

    Citation Envoyé par sioux
    Sinon avec les TEvent je suppose que l'idée ces que le thread "active" le TEvent du composant, en lieu et place de PostThreadMessage.
    Oui, de manière à signaler que quelque chose s'est passé (vraiment au hasard, un message a été posté...)

    Citation Envoyé par sioux
    Et que le composant Test l'état des TEvent régulierement.
    Non : en fait, c'est l'application qui le fait en appelant des méthodes du composant.

    Citation Envoyé par sioux
    Mais la quand j'ai des parametres a passer ça coince
    Ben justement, l'évènement peut te servir à dire 'Des messages de thread sont à dépiler". Mais en général, on utilise un thread intermédiaire quand même.

    N'hésites pas à poser des questions : le sujet est vaste et plutôt complexe, c'est donc normal que tu "patauges" un peu au début.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  5. #25
    Membre émérite Avatar de edam
    Homme Profil pro
    Développeur Delphi/c++/Omnis
    Inscrit en
    Décembre 2003
    Messages
    1 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : Développeur Delphi/c++/Omnis
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 894
    Points : 2 770
    Points
    2 770
    Par défaut
    pardon si je vous dérange,mais j'ai une question qui me chatoiye
    Citation Envoyé par Mac LAK
    Oui, parcequ'il y en a une pour la répétition du thread et une pour la boucle de message. Non, parceque la boucle de message ne traite pas le cas Terminated.
    le terminated qui est testé par le tréade comment il est modifier théchniquement?
    dans une section critique, ou avec un messagethréad ou qoi????
    merci de votre attention
    PAS DE DESTIN, C'EST CE QUE NOUS FAISONS

  6. #26
    Expert éminent sénior

    Avatar de sjrd
    Homme Profil pro
    Directeur de projet
    Inscrit en
    Juin 2004
    Messages
    4 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Directeur de projet
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2004
    Messages : 4 517
    Points : 10 154
    Points
    10 154
    Par défaut
    Par un appel à Terminate (souvent en dehors du thread).
    sjrd, ancien rédacteur/modérateur Delphi.
    Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
    Découvrez Mes tutoriels.

  7. #27
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Au "coeur", ça peut aussi être par un appel aux fonctions de type InterlockedIncrement (API Win32)
    Dans Delphi, le passage à True de la propriété Terminated n'est pas protégé, parceque :
    - Sa valeur par défaut est False,
    - La propriété Terminated est en lecture seule,
    - Même si plusieurs threads modifient l'attribut FTerminated simultanément, ils vont tous y mettre la même valeur, à savoir True.
    - Il n'existe aucune méthode pour positionner FTerminated à la valeur False.

    Donc, l'attribut est protégé contre les accès concurrents parcequ'aucun mode d'accès n'est, justement, susceptible de produire un interblocage.
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

  8. #28
    Membre émérite Avatar de edam
    Homme Profil pro
    Développeur Delphi/c++/Omnis
    Inscrit en
    Décembre 2003
    Messages
    1 894
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Maroc

    Informations professionnelles :
    Activité : Développeur Delphi/c++/Omnis
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 894
    Points : 2 770
    Points
    2 770
    Par défaut
    Citation Envoyé par Mac LAK
    Au "coeur", ça peut aussi être par un appel aux fonctions de type InterlockedIncrement (API Win32)
    ......
    - Même si plusieurs threads modifient l'attribut FTerminated simultanément, ils vont tous y mettre la même valeur, à savoir True.
    c'est ce que j'aime bien savoir et surtou si possible avec un peut de détail
    surtout à
    Citation Envoyé par Mac LAK
    - Même si plusieurs threads modifient l'attribut FTerminated simultanément,
    sans y avoir de choque
    si plus d'un tréad surmant les dérnier seront bloqué jusqu'a ce que les premié termine leur apel a terminate...???
    c'est un question un peut stupide je pense mais j'aime bien savoir ce que Mr delphi fait ?????
    PAS DE DESTIN, C'EST CE QUE NOUS FAISONS

  9. #29
    Inactif  
    Avatar de Mac LAK
    Profil pro
    Inscrit en
    Octobre 2004
    Messages
    3 893
    Détails du profil
    Informations personnelles :
    Âge : 50
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations forums :
    Inscription : Octobre 2004
    Messages : 3 893
    Points : 4 846
    Points
    4 846
    Par défaut
    Citation Envoyé par edam
    Citation Envoyé par Mac LAK
    - Même si plusieurs threads modifient l'attribut FTerminated simultanément,
    sans y avoir de choque
    si plus d'un tréad surmant les dérnier seront bloqué jusqu'a ce que les premié termine leur apel a terminate...???
    c'est un question un peut stupide je pense mais j'aime bien savoir ce que Mr delphi fait ?????
    Non, car FTerminated est un attribut propre à chaque thread, donc lorsque tu demande à un thread de se terminer, ça ne touche pas les autres, du moins pas avant d'arriver vraiment au coeur de l'API Win32 (mais là, pas la peine de demander, j'en sais rien !! ;-)).
    Mais si plusieurs threads demandent à un thread T de se terminer, il ne peut pas y avoir conflit car tous vont demander à écrire la même valeur, donc pas de risque d'écrasement d'une valeur importante.

    Le seul risque réel, c'est si certains threads demandant la fermeture "traînent" en longueur par rapport aux autres (c'est surtout un problème de priorités des threads, en général) : il est possible que le thread soit déjà détruit => une exception sera levée, mais c'est tout ce que tu risques.

    C'est pour cette raison que, même si c'est possible, on laisse en général le soin de terminer un thread à son thread "créateur" : c'est plus clean.

    C'est OK pour toi ?
    Mac LAK.
    ___________________________________________________
    Ne prenez pas la vie trop au sérieux, de toutes façons, vous n'en sortirez pas vivant.

    Sources et composants Delphi sur mon site, L'antre du Lak.
    Pas de question technique par MP : posez-la dans un nouveau sujet, sur le forum adéquat.

    Rejoignez-nous sur : Serveur de fichiers [NAS] Le Tableau de bord projets Le groupe de travail ICMO

Discussions similaires

  1. Arret d'un thread sans message d'erreur
    Par Beujator dans le forum ASP.NET
    Réponses: 6
    Dernier message: 24/07/2009, 10h25
  2. Closer un thread de message d'attente proprement
    Par Vonziz dans le forum Windows Forms
    Réponses: 6
    Dernier message: 06/04/2009, 16h52
  3. [Thread] Boucle à message
    Par homeostasie dans le forum Visual C++
    Réponses: 6
    Dernier message: 23/10/2007, 17h37
  4. Thread et messages
    Par yonderboy dans le forum Delphi
    Réponses: 3
    Dernier message: 17/01/2007, 17h33

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo