c++ - 使用内存映射文件进行持久化 - 是否需要 volatile?

标签 c++ volatile memory-mapped-files boost-interprocess

我需要在重新启动时持久保留 uint64_t 标记。

为了实现这一点,我使用 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_ 是非 volatile 的,并且对内存映射区域执行 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_ 的进程,或者它是否只是偶然工作,实际上是未定义的行为。

最佳答案

在这种情况下,没有。

在幕后,Boost 的 interprocess/mapped_region.hpp 正在使用 mmap,它将返回一个指向内存映射区域的指针。

如果您怀疑另一个进程(或硬件)可能正在写入您的文件,您只需要使用 volatile

(这将是您应该提供的最基本的同步,因为 volatile 强制在每次访问时从内存中读取。如果您可以控制进程,您可以尝试更高级的同步,如信号量.)

关于c++ - 使用内存映射文件进行持久化 - 是否需要 volatile?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45557974/

相关文章:

Java 数组 : synchronized + Atomic*, 或同步就足够了吗?

multithreading - 这里需要 volatile 吗?

c++ - 如何在不配置新工具链的情况下告诉 Bazel 使用哪个编译器

c++ - 用 C++ (OpenCV) 读取像素值

c++ - 为什么 std::atomic 中的所有成员函数都带有和不带有 volatile?

java - 将文件用于共享内存 IPC

r - 测试缓冲区是否已在 R 中刷新

c# - MemoryMappedFile 不适用于 2 个进程?

c++ - 动态创建包含另一个动态创建的结构数组的结构数组时的内存管理

C++ 无法从函数返回对象