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.
I pensée volatile était seulement nécessaire si quelque chose d'autre que votre programme écrivait dans ce fichier? – AndyG
@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 –