8

In boost::interprocess documentation it is said as requirement for containers to be stored in shared memory:

  1. STL containers may not assume that memory allocated with an allocator can be deallocated with other allocators of the same type. All allocators objects must compare equal only if memory allocated with one object can be deallocated with the other one, and this can only tested with operator==() at run-time.
  2. Containers' internal pointers should be of the type allocator::pointer and containers may not assume allocator::pointer is a raw pointer.
  3. All objects must be constructed-destroyed via allocator::construct and allocator::destroy functions.

I am using gcc 4.7.1 with -std=c++11 (and boost 1.53). Is it safe to use the below defined ShmVector type?

typedef boost::interprocess::allocator<int,
    boost::interprocess::managed_shared_memory::segment_manager>  ShmemAllocator;
typedef std::vector<int, ShmemAllocator> ShmVector;

I tried a dummy process which uses this type, and it looks it is working, but I am still not sure that the vector in gcc4.7.1 does satisfy all the requirements. I am especially not sure about the first requirement.

#include <iostream>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <vector>
#include <cstdlib> //std::system

typedef boost::interprocess::allocator<int,
        boost::interprocess::managed_shared_memory::segment_manager>  ShmemAllocator;
typedef std::vector<int, ShmemAllocator> ShmVector;

int main(int argc, char *argv[])
{
    if(argc == 1){ //Parent process

        struct shm_remove
        {
            shm_remove() { boost::interprocess::shared_memory_object::remove("MySharedMemory"); }
            ~shm_remove(){ boost::interprocess::shared_memory_object::remove("MySharedMemory"); }
        } remover;

        //Create a new segment with given name and size
        boost::interprocess::managed_shared_memory segment(boost::interprocess::create_only,
                "MySharedMemory", 65536);

        //Initialize shared memory STL-compatible allocator
        const ShmemAllocator allocator(segment.get_segment_manager());

        ShmVector* v = segment.construct<ShmVector>("ShmVector")(allocator);
        v->push_back(1); v->push_back(2); v->push_back(3);

        //Launch child process
        std::string s(argv[0]); s += " child ";
        if(0 != std::system(s.c_str()))
            return 1;

    } else { // Child process

        //Open the managed segment
        boost::interprocess::managed_shared_memory segment(
                boost::interprocess::open_only, "MySharedMemory");

        //Find the vector using the c-string name
        ShmVector *v = segment.find<ShmVector>("ShmVector").first;

        for (const auto& i : *v) {
            std::cout << i << " ";
        }
        std::cout << std::endl;

    }
}
4

3 回答 3

0

在 C++ 11 中,分配器规则略有变化,但我认为它不会影响您的问题。

您可能想先了解标准对此有何规定。但是您实际上想要检查您的特定 STL 实现是否符合标准并且不包含错误。

对于第二部分,我强烈建议您去来源并检查一下,实际上并不难。

此外,您可以编写测试以查看它是否真正正常工作:

  • 创建自定义分配器:
    • 使用一些自定义类型作为指针,常量指针;
    • construct()中,destruct()计算调用次数;
  • 创建YourCustomType与分配器一起使用,该分配器还计算构造/破坏的数量。
  • 现在,创建std::vetor<YourCustomType, YourCustomAllocator<YourCustomType>>实例,插入一些元素,清除向量,销毁它,看看是否:
    • 调用次数construct() destruct()等于 的构造破坏次数YourCustomType
    • typeid(YourCustomAllocator::pointer) == typeid(std::vetor<YourCustomType, YourCustomAllocator<YourCustomType>>::pointer)

这样您就可以确保所有限制都适用。

至于问题的第一部分,这是一个旧的 C++ 标准(不是 C++ 11)。

1没有办法(正确实施)向量将分配器无处不在。它将使用您提供的任何分配器,并将其用于一切。至于 operator==,它是在 boost 的分配器中实现的,因此让 operator== 按需要工作是 boost 的问题。虽然我无法在标准中找到确认。

2除非有错误,否则std::vector<T, YourAllocator>::pointer应该是分配器的指针。cppreference.com 这么说,标准这么说,(查找“模板类向量”):

    typedef typename Allocator::pointer               pointer;
    typedef typename Allocator::const_pointer         const_pointer;

尽管相同的标准对分配器有这样的规定:本国际标准中描述的容器的实现被允许假设它们的分配器模板参数满足表 6 中的以下两个附加要求。

-- 给定分配器类型的所有实例都必须是可互换的,并且总是相互比较相等。

--typedef 成员 pointer、const_pointer、size_type 和 difference_type 要求分别为 T*、T const*、size_t 和 ptrdiff_t。

所以,实际上标准不允许使用任何指针类型,但我的猜测是实际的 STL 实现会起作用。

3只需检查std::vector<T>::clear()方法实现,看看是否调用了 allocator::destroy。检查std::vector<T>::resize()方法的实现以查看是否使用了 allocator::construct。我无法在标准中找到调用破坏和构造的要求

于 2013-03-14T18:52:05.760 回答
0

我没有评论的声誉,所以我必须回答..如果两个分配器比较相等,它们是可以互换的。例如,比较不相等的相同类型的分配器可以用不同的(共享的)内存进行初始化。请参阅分配器

a1 == a2 => returns true only if the storage allocated by the allocator a1 can be deallocated through a2. Establishes reflexive, symmetric, and transitive relationship. Does not throw exceptions.

因此,如果您的ShmVector实例是使用ShmemAllocator比较相等的 s 创建的,那么您必须是安全的。

于 2019-05-27T19:52:32.423 回答
0

我认为答案是否定的。因为在实践中(在 C++98 中)和理论上(C++11 标准),std::vector指针不能是T*.

这就是为什么boost::interprocess::vector<T>使用boost::container::vector<T, boost::interprocess::allocator<T>>(而不是std::vector<T, boost::interprocess::allocator<T>>)。

于 2017-07-07T01:08:13.950 回答