我需要在重新啓動時持續保留uint64_t
標記。使用內存映射文件進行持久化 - 是否需要volatile?
要做到這一點,我使用boost::interprocess::mapped_region
內存映射,我在同一個進程創建一個文件:
bip::file_mapping file(filename.c_str(), bip::read_write);
auto region = std::make_unique<bip::mapped_region>(file, bip::read_write);
我再投地址到我的uint64_t
類型現在
using Tag = uint64_t;
Tag& curr_ = *reinterpret_cast<Tag*>(region->get_address());
我可以後增加標籤,獲得「下一個標籤」,並且結果在重新啓動後持續存在
Tag next = curr_++;
請注意,這個文件是寫入和從只讀通過這個過程。它的目的純粹是提供持久性。
問:
是我Tag& curr_
,是非易失性的,並且執行I/O的內存映射區域,不確定的行爲?
爲了正確,我的代碼是否需要volatile
關鍵字?
全部工作如下例子:
#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;
}
輸出:
在整個運行中,持久性被保持。
$ ./a.out
1
$ ./a.out
2
$ ./a.out
3
$ ./a.out
4
我不知道這是否是正確的,因爲我的過程是唯一一個從讀/寫Tag& curr_
,或者如果它只是偶然的工作,並且,事實上,不確定的行爲。
我如果您的程序以外的其他程序正在寫入該文件,則認爲易失性只是必要的? – AndyG
@AndyG,我也是這樣 - 但由於I/O調度器將處理實際的讀/寫磁盤,這是否被認爲是另一個過程?我的理解不是,並且volatile *不是必需的,但我不是100%確定的,因此,這個問題 –