2017-08-08 6 views
4

J'ai besoin de la persistance d'une balise uint64_t entre les redémarrages.Utilisation d'un fichier mappé en mémoire pour la persistance - est volatile requise?

Pour cela, je me sers boost::interprocess::mapped_region à la mémoire mapper un fichier que je crée dans le même processus:

bip::file_mapping file(filename.c_str(), bip::read_write); 
auto region = std::make_unique<bip::mapped_region>(file, bip::read_write); 

Je puis jeté l'adresse à mon uint64_t de type

using Tag = uint64_t; 
Tag& curr_ = *reinterpret_cast<Tag*>(region->get_address()); 

Maintenant, je peux balise post-incrément, obtenant la "balise suivante", et les résultats sont conservés à travers les redémarrages

Tag next = curr_++; 

Notez que ce fichier est écrit à et lu à partir deseulement par ce processus. Son but est purement de fournir la persistance.

Question:

est mon Tag& curr_, étant non volatile, et la réalisation d'E/S à une région cartographiée mémoire, comportement non défini-?

Pour être correct, mon code nécessite-t-il le mot-clé volatile?

exemple de travail complet ci-dessous:

#include <boost/interprocess/mapped_region.hpp> 
#include <boost/interprocess/file_mapping.hpp> 
#include <sys/stat.h> 
#include <fstream> 
#include <cstdint> 
#include <memory> 
#include <iostream> 

namespace bip = boost::interprocess; 

using Tag = uint64_t; 

Tag& map_tag(const std::string& filename, 
      std::unique_ptr<bip::mapped_region>& region) 
{ 
    struct stat buffer; 
    if (stat(filename.c_str(), &buffer) != 0) 
    { 
     std::filebuf fbuf; 
     fbuf.open(filename.c_str(), std::ios_base::in | 
            std::ios_base::out | 
            std::ios_base::trunc | 
            std::ios_base::binary); 

     Tag tag = 1; 
     fbuf.sputn((char*)&tag, sizeof(Tag)); 
    } 

    bip::file_mapping file(filename.c_str(), bip::read_write); 

    // map the whole file with read-write permissions in this process 
    region = std::make_unique<bip::mapped_region>(file, bip::read_write); 

    return *reinterpret_cast<Tag*>(region->get_address()); 
} 

class TagBroker 
{ 
public: 
    TagBroker(const std::string& filename) 
     : curr_(map_tag(filename, region_)) 
    {} 

    Tag next() 
    { 
     return curr_++; 
    } 

private: 
    std::unique_ptr<bip::mapped_region> region_; 
    Tag& curr_; 
}; 

int main() 
{ 
    TagBroker broker("/tmp/tags.bin"); 

    Tag tag = broker.next(); 

    std::cout << tag << '\n'; 
    return 0; 
} 

Sortie:

À travers pistes, la persistance est maintenue.

$ ./a.out 
1 
$ ./a.out 
2 
$ ./a.out 
3 
$ ./a.out 
4 

Je ne sais pas si cela est exact, puisque mon processus est la seule lecture de/écriture à Tag& curr_, ou si elle est juste par accident de travail, et est, en fait, un comportement non défini.

+0

I pensée volatile était seulement nécessaire si quelque chose d'autre que votre programme écrivait dans ce fichier? – AndyG

+0

@AndyG c'est ce que je pense aussi - mais étant donné que le planificateur d'E/S traitera la lecture/l'écriture sur le disque, est-ce considéré comme un autre processus?Ma compréhension n'est pas, et volatile * n'est pas * obligatoire, mais je ne suis pas sûr à 100%, d'où cette question –

Répondre

2

Dans ce cas, non.

Sous le capot, interprocess/mapped_region.hpp de Boost utilise mmap qui vous renverra un pointeur vers votre région mappée en mémoire.

Vous n'avez besoin d'utiliser volatile que si vous pensez qu'un autre processus (ou matériel) est en train d'écrire dans votre fichier.

(Ce serait la synchronisation les plus élémentaires que vous devez fournir, car volatile applique une lecture de la mémoire à chaque accès. Si vous avez le contrôle sur les processus, vous pouvez essayer la synchronisation plus avancée comme un sémaphores.)

+0

Donc pour ce cas d'utilisation particulier, quel est mon processus étant le ** seul à écrire dans le fichier ** , alors "volatile" n'est pas nécessaire, et aucune synchronisation plus avancée, comme le sémaphore, etc. –

+0

Exactement, monsieur – AndyG

+0

Merci pour votre aide! –