c++ - 当一个进程截断由 boost 进程间库创建的共享内存时,进程需要重新映射

标签 c++ boost shared-memory interprocess

当其中一个进程截断共享内存以动态增加大小时,Boost 进程间共享内存需要重新映射并再次获取地址。代码如下,在实际情况下,消费者 mapping 可以了解生产者 trunc 每次创建的新内存边界。然而,当 trunc 创建更大的内存时,当向 mapping 输入更大的偏移量时,映射将崩溃。

./trunc 10
./mapping
input 9, output is 9.
./trunc 10000, 
input 9999 to mapping process, then segmentation fault.

截断.cpp

#include <iostream>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>

namespace bi = boost::interprocess;

int main(int argc, char* argv[]) {
    bi::shared_memory_object shm(bi::open_or_create, "testshm", bi::read_write);
    shm.truncate(sizeof(int) * std::atoi(argv[1]));
    bi::mapped_region reg(shm, bi::read_write, 0);
    int* p = (int*)reg.get_address();
    for(std::size_t i = 0; i < std::atoi(argv[1]); ++i)
        p[i] = i;

    return 0;
}

映射.cpp

#include <iostream>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>

namespace bi = boost::interprocess;

int main(int argc, char* argv[]) {

    bi::shared_memory_object shm(bi::open_only, "testshm", bi::read_only);
    bi::mapped_region reg(shm, bi::read_only, 0);
    int* p = (int*)reg.get_address();
    do {
        std::cout << "Please input offset:" << std::endl;
        int offset;
        std::cin >> offset;
        std::cout << "Integer @" << offset << " is " << p[offset] << std::endl;


    } while(true);
    return 0;
}

最佳答案

在我的系统上不会发生这种情况。

遗憾的是,我无法在 Coliru 上直播(因为不支持共享内存),但您也许可以使用以下代码重新测试:

#include <iostream>
#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/mapped_region.hpp>

namespace bi = boost::interprocess;

static char const* const SHM_NAME = "sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4";

int main(int argc, char** argv) {
    if (argc>1) {
        bi::shared_memory_object shm(bi::open_or_create, SHM_NAME, bi::read_write);

        shm.truncate(sizeof(int) * std::atoi(argv[1]));
        bi::mapped_region reg(shm, bi::read_write);

        int* p = reinterpret_cast<int*>(reg.get_address());

        for(int i = 0; i < std::atoi(argv[1]); ++i)
            p[i] = i;

        std::cout << "Truncated and filled to " << reg.get_size() << "\n";
    } else {
        bi::shared_memory_object shm(bi::open_only, SHM_NAME, bi::read_only);
        bi::mapped_region reg(shm, bi::read_only, 0);

        size_t N = reg.get_size() / 4;
        int const* p = reinterpret_cast<int const*>(reg.get_address());

        size_t index;
        while (std::cout << "Please input index: " && std::cin >> index) {
            if (index < N)
                std::cout << "Integer @" << index << " is " << p[index] << "\n";
            else
                std::cout << "Index " << index << " out of bounds [0.." << N << ")\n";
        }
        std::cout << "Bye\n";
    }
}

它主要改变一些小的东西:

  • 名字
  • 检查大小是否被截断/在索引之前
  • 拼写reinterpret_cast
  • 常量正确性
  • truncmapping 合并到一个文件中

我测试它:

测试用例 1:trunc 10

./sotest 10
xxd /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4 | tail -5
ls -ltra /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4
./sotest <<< "0 1 2 3 999 9999 10000"

输出:

Truncated and filled to 40
00000000: 0000 0000 0100 0000 0200 0000 0300 0000  ................
00000010: 0400 0000 0500 0000 0600 0000 0700 0000  ................
00000020: 0800 0000 0900 0000                      ........
-rw-r--r-- 1 sehe sehe 40 jan  7 21:08 /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4
Please input index: Integer @0 is 0
Please input index: Integer @1 is 1
Please input index: Integer @2 is 2
Please input index: Integer @3 is 3
Please input index: Index 999 out of bounds [0..10)
Please input index: Index 9999 out of bounds [0..10)
Please input index: Index 10000 out of bounds [0..10)
Please input index: Bye

测试用例1:截断10000

sotest 10000
xxd /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4 | tail -5
ls -ltra /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4
./sotest <<< "0 1 2 3 999 9999 10000"

输出:

Truncated and filled to 40000
00009bf0: fc26 0000 fd26 0000 fe26 0000 ff26 0000  .&...&...&...&..
00009c00: 0027 0000 0127 0000 0227 0000 0327 0000  .'...'...'...'..
00009c10: 0427 0000 0527 0000 0627 0000 0727 0000  .'...'...'...'..
00009c20: 0827 0000 0927 0000 0a27 0000 0b27 0000  .'...'...'...'..
00009c30: 0c27 0000 0d27 0000 0e27 0000 0f27 0000  .'...'...'...'..
-rw-r--r-- 1 sehe sehe 40000 jan  7 21:08 /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4
Please input index: Integer @0 is 0
Please input index: Integer @1 is 1
Please input index: Integer @2 is 2
Please input index: Integer @3 is 3
Please input index: Integer @999 is 999
Please input index: Integer @9999 is 9999
Please input index: Index 10000 out of bounds [0..10000)
Please input index: Bye

测试用例1:trunc 10001

sotest 10001
xxd /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4 | tail -5
ls -ltra /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4
./sotest <<< "0 1 2 3 999 9999 10000"

输出:

Truncated and filled to 40004
00009c00: 0027 0000 0127 0000 0227 0000 0327 0000  .'...'...'...'..
00009c10: 0427 0000 0527 0000 0627 0000 0727 0000  .'...'...'...'..
00009c20: 0827 0000 0927 0000 0a27 0000 0b27 0000  .'...'...'...'..
00009c30: 0c27 0000 0d27 0000 0e27 0000 0f27 0000  .'...'...'...'..
00009c40: 1027 0000                                .'..
-rw-r--r-- 1 sehe sehe 40004 jan  7 21:08 /dev/shm/sotest-5b4f4154-0c7a-48f4-9be6-33b99094cea4
Please input index: Integer @0 is 0
Please input index: Integer @1 is 1
Please input index: Integer @2 is 2
Please input index: Integer @3 is 3
Please input index: Integer @999 is 999
Please input index: Integer @9999 is 9999
Please input index: Integer @10000 is 10000
Please input index: Bye

如果这在您的系统上给出了不同的结果,请告诉我。还有,举报 平台详细信息/版本使用了这种情况。

关于c++ - 当一个进程截断由 boost 进程间库创建的共享内存时,进程需要重新映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48139280/

相关文章:

c++ - std::vector 与 std::list 的插入频率和动态大小

php - 在 php 和 c 中使用共享内存?

c++ - Visual C++ 2017错误?编译器优化表达式

c++ - 未调用继承的重写方法

c++ - 当我们进行向下转型时内部会发生什么?

c++ - 将 boost::shared_lock 升级为独占锁

c++ - Boost 1.59.0 如何清理项目?

c++ - 调用另一个函数重载

c++ - 与信号量共享内存同步

c++ - 即使已指定,Visual Studio C++ 程序也找不到包含文件夹