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 C++ Discussion :

Ecriture "crash safe" dans un fichier


Sujet :

Langage C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Inscrit en
    Décembre 2003
    Messages
    87
    Détails du profil
    Informations forums :
    Inscription : Décembre 2003
    Messages : 87
    Par défaut Ecriture "crash safe" dans un fichier
    Bonjour,

    Dans mon application j'utilise un fichier xml pour sauvegarder l'état de différentes variables. Le but est qu'en cas de redémarrage de l'application (du pc) celle ci reprenne son exécution la ou elle c'était arrêtée. Mon problème est que si je tire la prise du PC / kill mon appli au moment de l'écriture les données contenues dans le fichier sont corrompues.

    Y a t'il un moyen d'éviter ce problème? Je pensais à une solution du genre écrire dans un fichier temporaire puis le déplacer pour écraser le fichier persistant.

    Petite précision au cas ou, je travaille sous linux et compile avec g++.

    Merci d'avance pour vos suggestions.

  2. #2
    Membre éprouvé
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    118
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 118
    Par défaut
    Tu pourrais peut être penser à un thread qui s'occuperait de scruter à intervalle régulier (de manière à ne pas surcharger le scheduleur) les variables à sauvegarder, et en cas de modification de ces variables (qui auraient été initialisées au préalable de manière à déterminer si oui ou non elles auraient été modifiées), le thread se chargerait d'écrire dans le fichier XML. De la sorte, ton fichier XML de sauvegarde serait constamment à jour, les risques de données corrompues sont fortement réduis mais pas totalement éliminés.

  3. #3
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    Il y a, malheureusement, des limites à ce que l'on peut faire... : Si on débranche la prise, rien ni personne n'aura le temps d'appliquer aucune procédure garantissant à 100% qu'il sera possible de reprendre l'exécution du programme exactement là où il s'est arrêté.

    Par contre, on peut effectivement décider de recourrir (quelle horreur) à un singleton ou, ( beaucoup ) mieux, à un "monostate" dont le destructeur enregistrerait un état particulier de l'application et les quelques manipulations à effectuer, un peu à la manière d'un script à effectuer.

    Nous partirions alors vers quelque chose proche de
    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
    /* l'objet qui sera sauvegardé à la destruction */
    class Restorable
    {
        public:
            ~Restorable()
            {
                /* je fais simple, mais on peut partir sur boost::archive et
                 * / ou boost::serialization, par exemple
                 */
                std::ofstream ofs("resotre.txt");
                saveState(ofs);
                saveActions(ofs);
            }
            void addAction(Action * toadd)
            {
                actions.push_back(toadd);
            }
            void execute()
            {
                while(!actions.empty())
                {
                    /* exécuter la première action à effectuer
                     * chaque action modifie state ;-)
                     */
                    *(actions.begin())->execute();
                     delete *(actions.begin());
                     actions.pop_front();
                }
            }
            void saveState(std::ofstream& ofs)
            {
                /* ici, on sauvegarde l'état courent */
            }
            void saveActions(ofs)
            {
                while(!actions.empty())
                {
                    /* sauvegarde des actions restantes
                     */
                    *(actions.begin())->save(ofs);
                     delete *(actions.begin());
                     actions.pop_front();
                }
            }
        private:
            /* un "état" représentant les données à un moment donné */
            State state;
            std::list<Action* > actions;
    }
    /* le "monostate" qui gère effectivement les actions à 
     * entreprendre
     */
    class ActionManager
    {
        public:
            void addAction(Action * toadd)
            {
                toRestore.addAction(toadd);
                toRestore.execute();
            }
        private:
            static Resotrable toRestore;
    };
    /* dans un *.cpp */
    Restorable ActionManager::toRestore = Restorable();
    Chaque fois que tu as une action à effectuer, il ne te "reste" plus qu'à passer par ton "ActionManager" pour la gérer, sous une forme proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    int main()
    {
        Action *theAction = new ConcreteAction(/* parametres */);
        ActionManager man;
        man.addAction( theAction );
    }
    l'objet toRestore sera, d'office, détruit au moment de quitter l'application, ce qui provoquera normalement la sauvegarde tant de l'état actuel que pour les actions restant à entreprendre
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  4. #4
    Membre confirmé
    Inscrit en
    Décembre 2003
    Messages
    87
    Détails du profil
    Informations forums :
    Inscription : Décembre 2003
    Messages : 87
    Par défaut
    Merci pour ces réponses. En fait le but c'est pas forcement de reprendre l’exécution exactement ou elle s'est arrêtée. Si on manque les changements des 5 dernières secondes c'est pas grave. Par contre le but est que cela fonctionne même si on tire la prise donc la solution de sauvegarder dans le destructeur ne s'applique pas ici.

    Je me demandais par contre si l'utilisation de rename éviterai que le fichier soit corrompu. Mon idée serait d'écrire dans un fichier temporaire temp.xml et après chaque écriture faire: rename("temp.xml", "persistent.xml");. Mais peut-être que je me trompe et que cette solution ne change absolument rien...

  5. #5
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par piemur2000 Voir le message
    Merci pour ces réponses. En fait le but c'est pas forcement de reprendre l’exécution exactement ou elle s'est arrêtée. Si on manque les changements des 5 dernières secondes c'est pas grave. Par contre le but est que cela fonctionne même si on tire la prise donc la solution de sauvegarder dans le destructeur ne s'applique pas ici.
    <mode petite histoire : on> Je regardais ce week end un reportage sur un crash d'avion qui, par chance, n'avait pas fait de victimes...

    Les enquêteurs s'étonnaient qu'un appareil de sauvegarde ne donnait pas les données relatives aux 45 dernières secondes avant le crash, et se sont donc, naturellement, dirigés vers "un problème électrique"...

    Jusqu'au moment où ils se sont rendus compte que le dit appareillage collectait énormément de données toutes les secondes puis les "compilait" pendant... 45 secondes avant de les enregistrer.

    L'appareil n'était absolument pas tombé en panne avant le crash, simplement, il avait cessé de fonctionné suite au crash, et donc, il y avait 45 secondes qui n'avaient simplement pas pu être sauvegardées, parce que en cours de traitement lorsque "tout s'est éteint"...
    <mode petite histoire : off >

    Comme je te l'ai dit, il est possible de se prémunir contre les impondérables, mais seulement jusqu'à un certain point...

    Tu pourrais, par exemple, envisager la mise en place d'un timer qui provoquerait de manière systématique la sauvegarde à intervale régulier (durant l'exécution "correcte" de l'application), voir une sauvegarde "avant plantage", mais RIEN, je le répète, ne t'offrira la moindre garantie au cas où tu te prendrais les pieds dans les cables
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Membre éclairé

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Par défaut
    Il serait peut-être possible qu'à chaque fois qu'une donnée change, un Event soit émit. Il serait alors possible de le catch et soit sauvegarder les changements à ce moment la, soit activer un bool, notifiant un thread externe qu'il existe des changements. Le thread externe pourrait simplement regarder à intervals réguliers s'il existe des changements et si oui les sauvegarder.

  7. #7
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Par défaut
    Salut,

    Citation Envoyé par koala01 Voir le message
    Par contre, on peut effectivement décider de recourrir (quelle horreur) à un singleton ou, ( beaucoup ) mieux, à un "monostate"
    C'est un peu HS par rapport au sujet mais comme j'ai vu cette phrase reprise par ailleur, je me permets d'intervenir : un monostate n'est pas beaucoup mieux ni même un peu mieux qu'un singleton. Pour moi, monostate/singleton/variable globale/variable de classe/variable statique à l'intérieur d'une fonction sont tous des états globaux, apportent les mêmes problèmes et sont donc équivalents.

    Pour continuer à marteler mon avis, mieux vaut s'auto-citer : ici et pour continuer le débat : la nouvelle discussion de notre amis dragonjoker suite aux quelques mots de Koala ci-dessus.

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

Discussions similaires

  1. Réponses: 12
    Dernier message: 22/04/2009, 13h02
  2. Ecriture d'un code hexadecimale dans un fichier...
    Par kore62 dans le forum Langage
    Réponses: 2
    Dernier message: 13/09/2008, 18h03
  3. Ecriture et lecture de class dans un fichier
    Par Dam06 dans le forum C++
    Réponses: 1
    Dernier message: 17/04/2008, 10h25
  4. Ecriture d'un seul bit dans un fichier
    Par fantomasmusic dans le forum Entrée/Sortie
    Réponses: 4
    Dernier message: 31/01/2005, 19h21

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