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

C++Builder Discussion :

TThread : EAccesViolation + EOSError


Sujet :

C++Builder

  1. #1
    Membre habitué Avatar de Rodrigue
    Inscrit en
    Août 2002
    Messages
    487
    Détails du profil
    Informations forums :
    Inscription : Août 2002
    Messages : 487
    Points : 157
    Points
    157
    Par défaut TThread : EAccesViolation + EOSError
    Bonjour,

    Voilà je vous explique mon problème :
    Je crée un nouveau projet très simpe avec Builder :
    - une TThread
    - un bouton
    - un Label

    Dans le TThread, je ne met rien si ce n'est un : ";" dans sa méthode Execute();
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    //---------------------------------------------------------------------------
    void __fastcall MyThread ::Execute()
    {
      ; //There is nothing or I just put a Sleep(10)!
    }
    //---------------------------------------------------------------------------
    Dans mon bouton, je crée dynamiquement ma Thread :
    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
     
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
     MyThread = new MyThread (false);
     MyThread ->OnTerminate = MyThread _End;
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::MyThread _End(TObject* Sender)
    {
     if(MyTHREAD)
     {
      delete MyTHREAD;
      MyTHREAD = NULL;
     }
     
     Label1->Caption = "Thread terminée";
    }
    //---------------------------------------------------------------------------
    et je l'efface lorsqu'elle est finie.
    J'exécute le programme et je n'ai aucune erreur! Tout fonctionne parfaitement... où est le problème alors ?

    Le problème survient quand je colle un objet suiConvertor sur ma fiche. Pour ceux qui ne connaissent pas, suiConvertor est un objet des composants SUIPack qui permettent de changer le skin d'une application. Donc, comme je le disais, je pose cette objet sur la fiche je choisis, par exemple, le style MacOSX. Et mnt, je compile... je lance mon application, je clique sur le bouton! Booooooom : le Debugger de Borland s'affole => une exception a été générée...
    ---------------------------
    Application Error
    ---------------------------
    Exception EAccessViolation in module rtl60.bpl at 000058C4.
    Access violation at address 400058C4 in module 'rtl60.bpl'. Read of address 00000010.
    ---------------------------
    OK
    ---------------------------

    ---------------------------
    Debugger Exception Notification
    ---------------------------
    Project Project2.exe raised exception class EOSError with message 'System Error. Code: 5.
    Accès refusé'. Process stopped. Use Step or Run to continue.
    ---------------------------
    OK Help
    ---------------------------

    ---------------------------
    Project2.exe
    ---------------------------
    Abnormal program termination
    ---------------------------
    OK
    ---------------------------
    Et hop' le programme se ferme tout seul!!! Incroyable non ? Alors où est-ce que je fais une erreur ? Pensez-vous que ça provienne des composants SUIPack? Peut-être ne supporte-t-il pas les threads... peut-être est-ce la méthode Synchronize()? Je n'en sais rien !

    Un grand merci d'avance!

    Cordialement,

  2. #2
    Membre chevronné
    Avatar de DjmSoftware
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Mars 2002
    Messages
    1 044
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Responsable de compte
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 044
    Points : 2 187
    Points
    2 187
    Billets dans le blog
    1
    Par défaut
    Salut,
    tu essaye de détruire ton thread dans le gestionnaire d'évennement survenant juste avant sa destruction.
    tu peux utiliser une Liste d'objects pe(TList)que tu libèrera a la fin de ton programme
    ci joint un code d'exemple
    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
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
     
    //---------------------------------------------------------------------------
     
    #ifndef Unit1H
    #define Unit1H
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    #include <Controls.hpp>
    #include <StdCtrls.hpp>
    #include <Forms.hpp>
    #include "Unit2.h"
    //---------------------------------------------------------------------------
    class TForm1 : public TForm
    {
    __published:	// Composants gérés par l'EDI
            TLabel *Label1;
            TButton *Button1;
            void __fastcall Button1Click(TObject *Sender);
            void __fastcall FormDestroy(TObject *Sender);
    private:	// Déclarations de l'utilisateur
         TList * MList;
    public:		// Déclarations de l'utilisateur
            __fastcall TForm1(TComponent* Owner);
    };
    //---------------------------------------------------------------------------
    extern PACKAGE TForm1 *Form1;
    //---------------------------------------------------------------------------
    #endif
     
    .cpp
    #include <vcl.h>
    #pragma hdrstop
     
    #include "Unit1.h"
     
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
    {
      MList=new TList();
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
      Label1->Caption="";
      TmThread* MyThread  = new TmThread(false);
      MList->Add(MyThread);
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::FormDestroy(TObject *Sender)
    {
     for (int n=0;n<MList->Count;n++)
       {
        TmThread* MyThread=(TmThread*)MList->Items[n];
        MyThread->Terminate();
        MyThread->WaitFor();
        delete MyThread;
       }
        delete MList;
    }
    //---------------------------------------------------------------------------
     
    .h du thread
    //---------------------------------------------------------------------------
     
    #ifndef Unit2H
    #define Unit2H
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    //---------------------------------------------------------------------------
    class TmThread : public TThread
    {
    private:
    protected:
            void __fastcall Execute();
    public:
            __fastcall TmThread(bool CreateSuspended);
    };
    //---------------------------------------------------------------------------
    #endif
    .cpp du thread
    //---------------------------------------------------------------------------
     
    #include <vcl.h>
    #pragma hdrstop
     
    #include "Unit2.h"
    #pragma package(smart_init)
    //---------------------------------------------------------------------------
     
    //   Important : les méthodes et les propriétés des objets de la VCL ne peuvent être
    //   utilisées que dans une méthode appelée en utilisant Synchronize, comme :
    //
    //      Synchronize(UpdateCaption);
    //
    //   où UpdateCaption serait de la forme :
    //
    //      void __fastcall TmThread::UpdateCaption()
    //      {
    //        Form1->Caption = "Mise à jour dans un thread";
    //      }
    //---------------------------------------------------------------------------
     
    __fastcall TmThread::TmThread(bool CreateSuspended)
            : TThread(CreateSuspended)
    {
     
    }
    //---------------------------------------------------------------------------
    void __fastcall TmThread::Execute()
    {
    while(!Terminated)
     {
      Sleep(10);
     }
    }
    //---------------------------------------------------------------------------
    cordialement

  3. #3
    Membre habitué Avatar de Rodrigue
    Inscrit en
    Août 2002
    Messages
    487
    Détails du profil
    Informations forums :
    Inscription : Août 2002
    Messages : 487
    Points : 157
    Points
    157
    Par défaut
    Salut DjmSoftware,

    Tout d'abord merci pour ta réponse. J'ai bien lu ton post ... mais ta méthode suppose que je laisse mon Thread tourné pendant toute la durée de l'éxécution de mon programme (ce qui n'est pas le cas ). Super méthode quand même, je l'ai mise à place

    tu essaye de détruire ton thread dans le gestionnaire d'évennement survenant juste avant sa destruction.
    Ben, je ne dis pas à ma Thread FreeOnTerminante donc je ne vois pas pourquoi elle se détruirait toute seule ? Peut-être que j'ai pas capté qqchose avec les Threads j'en suis au début de leur utilisation

    Donc en fait, je crée ma Thread en cliquant sur le bouton et quand elle est terminée (c'est facile il n'y a rien dedans)... elle va dans son "gestionnaire d'évènement" (cf.DjmSoftware). De là je libère sa mémoire... Peut-être est-ce ça la faute ... Je me suis inspiré du tutoriel sur les Threads de cgi et, sauf erreur de ma part, il me semble qu'il procède de la même manière.

    J'insisterai encore sur le fait qu'aucune erreur ne survient lorsque je n'utilise pas d'objet suiConvertor... à mon avis ça doit provenir de cet objet! Enfin je n'en sais rien...

    Cordialement,
    Mais alors je la libère où et comment ?

  4. #4
    Membre chevronné
    Avatar de DjmSoftware
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Mars 2002
    Messages
    1 044
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Responsable de compte
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 044
    Points : 2 187
    Points
    2 187
    Billets dans le blog
    1
    Par défaut
    Salut,
    l'evènement OnTerminate est appelé en interne dans la classe TThread
    lorsque le Thread se termine --> sort de la méthode execute
    --> le chat se mord la queue et explosion thermo nucléaire de ton programme

    si tu veux que tes threads se teminent librement
    c'est très simple dans la méthode FormDestroy ne fait pas d'appel à WaitFor();
    cordialement

  5. #5
    Membre habitué Avatar de Rodrigue
    Inscrit en
    Août 2002
    Messages
    487
    Détails du profil
    Informations forums :
    Inscription : Août 2002
    Messages : 487
    Points : 157
    Points
    157
    Par défaut
    Super j'ai compris! Un grand merci
    Tout fonctionne impeccablement

  6. #6
    Membre habitué Avatar de Rodrigue
    Inscrit en
    Août 2002
    Messages
    487
    Détails du profil
    Informations forums :
    Inscription : Août 2002
    Messages : 487
    Points : 157
    Points
    157
    Par défaut
    Une toute dernière question :
    est-ce que si j'ajoute dans la méthode Execute() :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    this->FreeOnTerminate = true;
    Est-ce que ça libèrera la mémoire que j'ai allouée à la Thread automatiquement ? J'alloue la mémoire de cette manière :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    MyTHREAD* MyThread = new MYTHREAD(false);
    ...
    Il n'y a donc pas à faire de :
    à la fin ?

    Un grand merci!

    Cordialement,

  7. #7
    Membre chevronné
    Avatar de DjmSoftware
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Mars 2002
    Messages
    1 044
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Responsable de compte
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 044
    Points : 2 187
    Points
    2 187
    Billets dans le blog
    1
    Par défaut
    Salut,
    il n'est pas nécesssaire de faire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    this->FreeOnTerminate = true;
    FreeOnTerminate = true; suffit
    mais dans ce cas le pointeur MyThread ne sera pas liberé dans la pile
    --> Memory leak;
    je te rappelle le pointeur MyThread est stocké dans la pile ,alors que son contenu *MyThread est stocké dans le tas
    Cordialement

  8. #8
    Membre habitué Avatar de Rodrigue
    Inscrit en
    Août 2002
    Messages
    487
    Détails du profil
    Informations forums :
    Inscription : Août 2002
    Messages : 487
    Points : 157
    Points
    157
    Par défaut
    Tant que j'ai qqun de compétent pour répondre à mes questions, j'en profite (sans trop abuser j'espère) !
    Mais alors est-ce dangereux de désallouer le pointeur MyThread à la fin de l'exécution de la Thread ??!
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    void __fastcall TForm1::MyThread_End(TObject* Sender)
    {
    	if(MyThread)
    	{
    		delete MyThread;
    		MyThread = NULL;
    	}
    }
    Voici comment je vois les choses :
    Ma Thread s'exécute... fait ce qu'elle a à faire et quand elle a fini, elle va dans la fonction MyThread_End qui n'appartient pas à la Thread... et la désalloue. Est-ce correct ? Ou est-ce que je pourrais encore avoir des erreurs de violation d'accès etc. en utilisant cette méthode ?

    Enfin, à quoi sert FreeOnTerminate = true s'il ne libère pas la Thread à la fin de son exécution ? Quand est-ce que je dois l'activer ?

    Merci beaucoup!

    Très cordialement,

  9. #9
    Membre chevronné
    Avatar de DjmSoftware
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Mars 2002
    Messages
    1 044
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Responsable de compte
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 044
    Points : 2 187
    Points
    2 187
    Billets dans le blog
    1
    Par défaut
    Salut,
    je crois que tu n'a pas bien compris ce que je t'ai expliqué

    aus sein d'une méthode une variable déclarée localement à la durée de vie de la méthode ce qui signifie que dés la sortie de la méthode la variable est détruite automatiquement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
       Label1->Caption="";
       TMThread* mthread=new TMThread(false);
    }
    le pointeur mthread dans la pile est détruit automatiquement a la sortie de la méthode Button1Click

    FreeOnTerminate quand a lui libère la mémoire attribue à l'object
    TMThread attribuée dans le tas

    quand a l'appel en sortie
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    void __fastcall TForm1::MyThread_End(TObject* Sender) 
    { 
       if(MyThread) 
       { 
          delete MyThread; 
          MyThread = NULL; 
       } 
    }
    il est a la fois inutile est dangereux car quand la méthode Execute de ton thread se termine cette méthode est appelée dans le thread Principal sans aucun égard à la synchronisation
    ce qui génére la plupart du temps des erreurs de synchronisation et des erreurs d'accès mémoire

    si tu veux utiliser des threads qui on une simple tache de fond a exécuter
    il vaut mieux utiliser des variables locales et FreeOnTerminate

    Exemple

    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
     
    .h du thread
    //---------------------------------------------------------------------------
    #ifndef Unit2H
    #define Unit2H
    //---------------------------------------------------------------------------
    #include <Classes.hpp>
    //---------------------------------------------------------------------------
    class TMThread : public TThread
    {
    private:
        void __fastcall UpdateCaption();
    protected:
            void __fastcall Execute();
    public:
            __fastcall TMThread(bool CreateSuspended);
    };
    //---------------------------------------------------------------------------
    #endif
    .cpp
    //---------------------------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop
     
    #include "Unit2.h"
    #include "Unit1.h"
    #pragma package(smart_init)
    //---------------------------------------------------------------------------
    //   Important : les méthodes et propriétés des objets de la VCL ne peuvent être
    //   utilisés que dans une méthode appelée en utilisant Synchronize, par exemple :
    //
    //      Synchronize(UpdateCaption);
    //
    //   où UpdateCaption pourrait être du type :
    //
    //      void __fastcall TMThread::UpdateCaption()
    //      {
    //        Form1->Caption = "Mise à jour dans un thread";
    //      }
    //---------------------------------------------------------------------------
    __fastcall TMThread::TMThread(bool CreateSuspended)
            : TThread(CreateSuspended)
    {
       FreeOnTerminate=true;
    }
    //---------------------------------------------------------------------------
    void __fastcall TMThread::Execute()
    {
        Sleep(1000); // simulation du job de ton thread
        Synchronize(UpdateCaption);
    }
    //---------------------------------------------------------------------------
     
     
    void __fastcall TMThread::UpdateCaption()
    {
      AnsiString Msg="Thread Terminé ";
      Msg+=IntToStr(ThreadID);
      Form1->Label1->Caption=Msg;
    }
     
    //.cpp de ta form sur laquelle est déposée un TButton et un TLabel
    //---------------------------------------------------------------------------
    #include <vcl.h>
    #pragma hdrstop
     
    #include "Unit1.h"
    #include "Unit2.h"
    //---------------------------------------------------------------------------
    #pragma package(smart_init)
    #pragma resource "*.dfm"
    TForm1 *Form1;
    //---------------------------------------------------------------------------
    __fastcall TForm1::TForm1(TComponent* Owner)
            : TForm(Owner)
    {
    }
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
       Label1->Caption="";
       TMThread* mthread=new TMThread(false);
    }
    //---------------------------------------------------------------------------
    Cordialement

  10. #10
    Membre habitué Avatar de Rodrigue
    Inscrit en
    Août 2002
    Messages
    487
    Détails du profil
    Informations forums :
    Inscription : Août 2002
    Messages : 487
    Points : 157
    Points
    157
    Par défaut
    Et la lumière fut... Là, j'ai tout compris

    Un grand merci !

  11. #11
    Membre habitué Avatar de Rodrigue
    Inscrit en
    Août 2002
    Messages
    487
    Détails du profil
    Informations forums :
    Inscription : Août 2002
    Messages : 487
    Points : 157
    Points
    157
    Par défaut
    Je n'en terminerai jamais avec ce problème...
    Tout ce que tu as dis fonctionne très très bien, il n'y a pas de problème à ce niveau là...

    Voilà, j'ai également un bouton STOP qui me permet comme son nom l'indique d'arrêter ma Thread. En gros l'intérieur de ma fonction Execute () de ma Thread est comme ceci :
    objet->Calcule(), prend bcp de temps et, possède une "méthode" qui permet d'arrêter le calcul. Cette "méthode" je l'appelle depuis le bouton STOP de ma Form.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
        MyThread->objet->END = true;
    Premièrement, est-ce que je peux faire ça comme ça ? A savoir changer la valeur d'une variable d'un objet qui a été déclaré dans ma Thread... ou alors je dois me synchroniser qd j'accède à cet objet ? Lors de mon "calcul" qui ce fait en boucle, on vérifie la valeur de cette variable à chaque boucle, on ne fait que la lire ... on n'écrit pas dedans.

    Deuxièmement, euh... ça ne marche plus avec une variable locale là ... alors comment faire pour effacer mon objet MyThread alloué dynamiquement (il y a sûrement un moyen de le faire, c'est quand même de la programmation de base ce que j'ai envie de faire : j'alloue de la mémoire et je la désalloue, ils ont pensé à comment on pourrait faire ça chez Borland, non?) ?

    Cordialement,

  12. #12
    Membre chevronné
    Avatar de DjmSoftware
    Homme Profil pro
    Responsable de compte
    Inscrit en
    Mars 2002
    Messages
    1 044
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Responsable de compte
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mars 2002
    Messages : 1 044
    Points : 2 187
    Points
    2 187
    Billets dans le blog
    1
    Par défaut
    Salut,
    tu peux appeler depuis ta Form des méthodes Public déclarées dans ton thread a la condition que ces méthodes ne soit pas bloquantes.

    c'est pourquoi il est préférable d'utiliser les méthodes hérithée de la classse TThread Suspend() et Resume()

    si tu ne peux pas utiliser de variables Locales alors dans ce cas utilise plutôt la solution que je t'ai expliquée dans mon permier post avec un object TList

    Cordialement

  13. #13
    Membre habitué Avatar de Rodrigue
    Inscrit en
    Août 2002
    Messages
    487
    Détails du profil
    Informations forums :
    Inscription : Août 2002
    Messages : 487
    Points : 157
    Points
    157
    Par défaut
    Ok ! MERCI

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Besoin de précision sur TThread
    Par psau dans le forum C++Builder
    Réponses: 2
    Dernier message: 15/02/2005, 23h35
  2. TThread et execl
    Par sebpatu dans le forum C++Builder
    Réponses: 2
    Dernier message: 17/11/2003, 00h02
  3. TThread et waitfor - descripteur non valide
    Par code34 dans le forum Langage
    Réponses: 2
    Dernier message: 27/10/2003, 23h44
  4. TThread: probleme de recuperation du Handle
    Par code34 dans le forum Langage
    Réponses: 8
    Dernier message: 07/09/2003, 03h04
  5. [TTHREAD] ne termine pas sont exécution
    Par Bbenj dans le forum Langage
    Réponses: 4
    Dernier message: 02/08/2002, 16h42

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