让进程间共享内存对象提振非共享副本:: [英] making non-shared copies of boost::interprocess shared memory objects

查看:90
本文介绍了让进程间共享内存对象提振非共享副本::的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经实现了设计在的boost ::进程间共享内存段中使用的各种类。他们所有的构造函数使用分配器<无效,segment_manager> 引用-一些明​​确在我写(定义如下面的构造函数)和一些简单的因为那是什么助推容器定义要求,在升压库code,我不应该被改变(如 IndexVector 下面)。

 的#include<升压/间/ managed_shared_memory.hpp>
#包括LT&;升压/间/分配器/ allocator.hpp>
#包括LT&;升压/间/集装箱/ vector.hpp>TYPEDEF的boost ::进程间:: managed_shared_memory段;
TYPEDEF的boost ::进程间:: managed_shared_memory :: segment_manager SegmentManager;
TYPEDEF的boost ::进程间::分配器<虚空,SegmentManager>分配器;类型定义为size_t指数;
TYPEDEF的boost ::进程间::分配器<指数SegmentManager> IndexAllocator;
TYPEDEF的boost ::进程间::矢量<指数IndexAllocator> IndexVector;Foo类
{
    上市:
        美孚(const的分配器和放大器;页头):MDATA(ALLOC){}
       〜富(){}    私人的:
        IndexVector MDATA;};

大多数情况下,这些对象坐在共享内存。但我有时想创建的的-shared存储它们的副本。我的问题是:我必须定义一个完全不同的类包含不同的成员类型(如 Foo_Nonshared )(的std ::矢量<索引> ,而不是我的共享 IndexVector 键入),并提供它们之间的复制/转换功能?这将是一个大量的工作,有很多愚蠢的重复。我可以通过类,它提供一个替代构造现有美孚减少重复,但我不知道如何初始化 IndexVector 成员没有一个分配器。

还是有一些不错的捷径?我想象某种特定的分配器例如,我可以传递给美孚(),并且将因此成为传递给 IndexVector 的构造,这将是既作为意为非共享内存分配的认可。难道这样的事情存在吗?是否有一个伪段经理管理香草非共享内存?或者是解决这个问题还有其他方法吗?

我希望为C ++ 03兼容的答案,尽管我也有兴趣去学习做事的C ++ 11 +的方式。

更新以下问题被标记为重复:我已阅读这些previous类似的问题:

和试图概括我看到那里,与一些成功和一些失败(请参阅下面的列表)。有几个编译器错误,我一直没能解决,标志着错误,尤其是我无法弄清楚如何实例化遍历这些高度元容器的成员方法。但有或没有这些错误,我还不能看到如何使模板-的模板成维护的解决方案(我的目的,在现实中,含有其它复杂的对象,其中包含进一步的容器,语法之外神智其中AFAICS复杂的容器。 ..看到部分标有哼)。

我想,到最后,我可能要重新设计,以避免在共享和堆内存相同的对象。

 的#include<升压/间/ managed_shared_memory.hpp>
#包括LT&;升压/间/分配器/ allocator.hpp>
#包括LT&;升压/间/集装箱/ vector.hpp>命名空间BIP =的boost ::进程间; //警告:C ++ 11别名声明模板< typename的T,模板< typename的...>类分配器> //警告:C ++ 11可变参数模板
    使用Vector = BIP ::矢量< T,分配器< T>取代; //警告:C ++ 11别名声明
//这似乎工作得到一些嵌套&LT的;>在控制湖。
//但我无法弄清楚如何创建一个迭代器这种类型(见下面的错误)//什么曾经是类现在是类模板模板<模板< typename的...>类分配器> //警告:C ++ 11可变参数模板
    一流的酒吧
    {
        上市:
             酒吧(常量分配器<无效>&安培;页头):薄荷糖(ALLOC){}
            〜栏(){}            报告无效(无效);        私人的:
            矢量< INT,分配器>薄荷糖;
    };模板<模板< typename的...>类分配器> //警告:C ++ 11可变参数模板
    Foo类
    {
        上市:
             美孚(const的分配器<无效>&安培;页头):毫巴(ALLOC){}
            〜富(){}            报告无效(无效);
        私人的:
            矢量<酒吧和LT;分配器>中分配器>毫巴; //嗯,有更复杂的结构这是怎么回事
                                                         //得到无法管理<嵌套<非常<快速> > > ...    };
//定义分配器模板模板< typename的T>
    使用HeapAllocator =的std ::分配器< T&GT ;; //警告:C ++ 11别名声明模板< typename的T>
    使用ShmemAllocator = BIP ::分配器< T,BIP :: managed_shared_memory :: segment_manager取代; //警告:C ++ 11别名声明//定义两个类变量:一个用于在堆上用途,一个用于在共享内存使用使用HeapFoo =富< HeapAllocator取代; //警告:C ++ 11别名声明
使用ShmemFoo =富< ShmemAllocator取代; //警告:C ++ 11别名声明//尝试定义的方法(因为失败的迭代器至今,
//但编译OK,如果函数体留空):模板<模板< typename的...>类分配器> //警告:C ++ 11可变参数模板
    空虚
    酒吧和LT;分配器> ::报告(无效)
    {
        性病::法院LT&;< [;
        矢量< INT,分配器>:迭代它;
//错误:^ ~~~~预期';'经过前pression
        对于(IT = mInts.begin();它+ = mInts.end();它++)
            性病::法院LT&;< (它== mInts.begin():?)LT;< *它;
        性病::法院LT&;< ] \\ n;
    }模板<模板< typename的...>类分配器> //警告:C ++ 11可变参数模板
    空虚
    美孚<分配器> ::报告(无效)
    {
        矢量<酒吧和LT;分配器>中分配器>:迭代它;
//错误:^ ~~~~预期';'经过前pression
        对于(IT = mBars.begin();它+ = mBars.end();它++)
            IT->报告();
        性病::法院LT&;< \\ n;
    }INT主要(无效)
{
    结构shm_remove
    {
         shm_remove(){BIP :: shared_memory_object ::删除(MySharedMemory); }
        〜shm_remove(){BIP :: shared_memory_object ::删除(MySharedMemory); }
    }卸妆;
    BIP :: managed_shared_memory赛格(BIP :: create_only,MySharedMemory,65536);    ShmemAllocator<无效> shalloc(seg.get_segment_manager());
    HeapAllocator<无效> halloc;    HeapFoo foo1(halloc);
    ShmemFoo foo2的(shalloc);
    foo1.Report();
    foo2.Report();
}


解决方案

好吧,你碰上经常恼人的Edgecase该模板,模板参数不是一等公民在C ++中(你不能将他们身边/的typedef他们):


  • 如何传送模板

我们该怎么办?


  1. 分配器::重新绑定< T>

    分配器有一个绑定机制,我pcisely敢说,因为这个$ P $。所以,你可以通过一个页头<无效> ,就好像它是开放的模板,因为你可以从那里通过做总是以同级分配器类型 ALLOC ::重新绑定< T> ::其他


  2. 添加到这样一个事实,即分配器通常有转换构造函数,这样做重新绑定,你并不需要在很多地方采取分配器过于具体


  3. 在C ++ 11, scoped_allocator 取值相继出台,以避免手动通过分配器在一些地方,会做元素的内部结构实例(例如 emplace_back )。

    有在地方的图书馆魔力,将自动从容器的 scoped_allocator 作为最后一个构造函数的参数(默认)添加分配器实例。提高集装箱库回迁的 scoped_allocator_adaptor 概念到C ++ 03,所以你可以使用它。


下面是将告诉您如何解决你过了,问题一个完整的示例还,你怎么可以混合使用共享内存的基于堆的酒吧实例实例:

  foo2.add(BAR1); //这个工程,因为...魔力!

这缘于该作品 scoped_allocator 上面提到的。

<大骨节病> 住在Coliru

 的#include&LT;升压/间/ managed_shared_memory.hpp&GT;
#包括LT&;升压/间/分配器/ allocator.hpp&GT;
#包括LT&;升压/间/集装箱/ vector.hpp&GT;
#包括LT&;升压/集装箱/ scoped_allocator.hpp&GT;命名空间BIP =的boost ::进程间;命名空间通用{    模板&LT; typename的T,typename的分配/ * =的std ::分配器&LT; T&GT; * /&GT;
        采用矢量= BIP ::矢量&lt; T,类型名的Alloc ::模板重新绑定&LT; T&GT; ::其他取代;    模板&LT;类型名的Alloc&GT;结构酒吧{
        的typedef的Alloc allocator_type;在//联系与uses_allocator / scoped_allocator        //只需要分配,如果不是默认 - 构造的
        酒吧(ALLOC的Alloc的Alloc =()):薄荷糖(ALLOC){}        //转换的构造函数,所以我们可以分配器之间的转换
        模板&LT; typename的OtherAlloc&GT;
            酒吧(酒吧及LT; OtherAlloc&GT;常量和放大器; RHS,分配的alloc =的Alloc())
                :薄荷糖(rhs.mInts.begin(),rhs.mInts.end(),分配)
            {
            }        报告无效()const的;        无效的add(int i)以{mInts.emplace_back(I) }      私人的:
        模板&LT; typename的OtherAlloc&GT;朋友结构吧; //我们可以看到对方的薄荷糖
        typedef的矢量&lt; INT,分配&GT; ints_t;
        ints_t薄荷糖;
    };    模板&LT;类型名的Alloc&GT;结构美孚{
        的typedef的Alloc allocator_type;在//联系与uses_allocator / scoped_allocator        美孚(ALLOC的Alloc的Alloc =()):毫巴(ALLOC){}
        报告无效()const的;        模板&LT; typename的酒吧&GT;
        无效的add(const的酒吧放与巴){mBars.emplace_back(巴); }      私人的:
        typedef的矢量&lt;酒吧和LT;的Alloc&gt;中的Alloc&GT; mbars_t;
        mbars_t毫巴;
    };
}命名空间堆{
    使用VAlloc =的std ::分配器&LT;无效取代;    用酒吧=通用::酒吧和LT; VAlloc取代;
    使用美孚=通用::美孚&LT; VAlloc取代;
}命名空间共享{
    使用VAlloc =的boost ::容器:: scoped_allocator_adaptor&LT; BIP ::分配器&LT;无效,BIP :: managed_shared_memory :: segment_manager&GT;取代;    用酒吧=通用::酒吧和LT; VAlloc取代;
    使用美孚=通用::美孚&LT; VAlloc取代;
}模板&LT;类型名的Alloc&GT;无效通用::酒吧和LT;&的Alloc GT; ::报告()const的{
    性病::法院LT&;&LT; [;
    对于(类型名ints_t ::为const_iterator吧= mInts.begin();它= mInts.end(!);它++)
        性病::法院LT&;&LT; (它== mInts.begin():?)LT;&LT; *它;
    性病::法院LT&;&LT; ] \\ n;
}模板&LT;类型名的Alloc&GT;
无效通用::美孚&LT;&的Alloc GT; ::报告()const的{
    对于(类型名mbars_t ::为const_iterator吧= mBars.begin();它= mBars.end(!);它++)
        IT-&GT;报告();
    性病::法院LT&;&LT; \\ n;
}诠释主要(无效){
    结构shm_remove {
        shm_remove(){BIP :: shared_memory_object ::删除(MySharedMemory); }
        〜shm_remove(){BIP :: shared_memory_object ::删除(MySharedMemory); }
    }卸妆;    ///////////////////////////////////
    //基于堆的:
    性病::法院LT&;&LT; 基于堆存储:\\ N的;    堆::美孚foo1;
    堆::酒吧BAR1;    bar1.add(42);
    bar1.add(2);
    bar1.add(-99);    foo1.add(BAR1);
    foo1.Report();    /////////////////////////////////
    性病::法院LT&;&LT; 共享存储器:\\ N的;
    BIP :: managed_shared_memory赛格(BIP :: create_only,MySharedMemory,65536);
    共享:: VAlloc shalloc(seg.get_segment_manager());    分享::富foo2的(shalloc);
    分享::酒吧BAR2(shalloc);    bar2.add(43);
    bar2.add(3);
    bar2.add(-98);    foo2.add(BAR2);当然//这工作
    foo2.add(BAR1); //这个工程,因为...魔力!
    foo2.Report();
}

打印:

 基于堆存储:
[42,2,-99]共享内存存储:
43,3,-98]
[42,2,-99]

I have implemented various classes that are designed to be used in boost::interprocess shared memory segments. All their constructors employ allocator<void,segment_manager> references—some explicitly in the definitions I have written (like the Foo constructor below) and some simply because that's what the boost container definition requires, in boost library code that I should not be changing (like the IndexVector below).

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/vector.hpp>

typedef boost::interprocess::managed_shared_memory                   Segment;
typedef boost::interprocess::managed_shared_memory::segment_manager  SegmentManager;
typedef boost::interprocess::allocator< void, SegmentManager >       Allocator;

typedef size_t                                                       Index;
typedef boost::interprocess::allocator< Index, SegmentManager >      IndexAllocator;
typedef boost::interprocess::vector<    Index, IndexAllocator >      IndexVector;

class Foo
{
    public:
        Foo( const Allocator & alloc ) : mData( alloc ) {}
       ~Foo() {}

    private:
        IndexVector mData;

};

Mostly, these objects sit in shared memory. But I sometimes want to create copies of them in non-shared memory. My question is this: do I have to define a whole different class (e.g. Foo_Nonshared) containing different member types (std::vector<Index> instead of my shared IndexVector type) and provide copy/conversion functions between them? That will be a lot of work and a lot of stupid duplication. I could reduce duplication by providing an alternative constructor to the existing Foo class, but then I wouldn't know how to initialize the IndexVector member without an allocator.

Or is there some nice shortcut? I'm imagining some sort of particular allocator instance that I can pass to Foo(), and which will hence be passed on to the IndexVector constructor, which will be recognized by both as meaning "allocate in non-shared memory". Does such a thing exist? Is there a "dummy segment manager" for managing vanilla non-shared memory? Or are there other ways around this problem?

I'm hoping for C++03-compatible answers even though I'm also interested to learn the C++11+ ways of doing things.

Update following question being marked as duplicate: I have read these previous similar questions:

and have tried to generalize what I see there, with some successes and some failures (see listing below). There are a few compiler errors that I haven't been able to resolve, marked ERROR—in particular I cannot figure out how to instantiate methods that iterate over the members of these highly "meta" containers. But with or without those errors, I cannot yet see how to make templates-of-templates into a maintainable solution (my objects, in reality, contain containers of other complex objects, which contain further containers, which AFAICS complicates the syntax beyond sanity... see the part marked "hmm").

I guess, in the end, I might have to re-design to avoid having the same objects in shared and heap memory.

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/vector.hpp>

namespace bip = boost::interprocess; // warning: C++11 alias declaration

template <typename T, template<typename...> class Allocator>  // warning: C++11 variadic template
    using Vector = bip::vector< T, Allocator<T>>;             // warning: C++11 alias declaration
// this seems to work to get some of the nested <>ness under control.
// But I can't figure out how to create an iterator to this kind of type (see errors below)

// what once were classes are now class templates

template <template<typename...> class Allocator>              // warning: C++11 variadic template
    class Bar
    {
        public:
             Bar( const Allocator<void> & alloc ) : mInts( alloc ) {}
            ~Bar() {}

            void Report( void );

        private:
            Vector< int, Allocator > mInts;
    };

template <template<typename...> class Allocator>              // warning: C++11 variadic template
    class Foo
    {
        public:
             Foo( const Allocator<void> & alloc ) : mBars( alloc ) {}
            ~Foo() {}

            void Report( void );


        private:
            Vector<  Bar<Allocator>, Allocator >  mBars; // hmm, with more complex structures this is going 
                                                         // to get unmanageably< nested< very< quickly > > > ...

    };


// Define allocator templates

template <typename T>
    using HeapAllocator  = std::allocator<T>; // warning: C++11 alias declaration

template <typename T> 
    using ShmemAllocator = bip::allocator<T, bip::managed_shared_memory::segment_manager>; // warning: C++11 alias declaration

// Define two class variants: one for use on the heap and one for use in shared memory

using HeapFoo  = Foo< HeapAllocator  >; // warning: C++11 alias declaration
using ShmemFoo = Foo< ShmemAllocator >; // warning: C++11 alias declaration

// Try to define methods (unsuccessful so far because of the iterators,
// but they compile OK if the function bodies are left empty):

template <template<typename...> class Allocator>              // warning: C++11 variadic template
    void
    Bar< Allocator >::Report( void )
    {
        std::cout << "[";
        Vector< int, Allocator >::iterator it;
// ERROR:     ^~~~~ expected ';' after expression
        for( it = mInts.begin(); it += mInts.end(); it++ )
            std::cout << ( it == mInts.begin() ? "" : ", " ) << *it;
        std::cout << "]\n";
    }

template <template<typename...> class Allocator>              // warning: C++11 variadic template
    void
    Foo< Allocator >::Report( void )
    {
        Vector< Bar< Allocator >, Allocator >::iterator it;
// ERROR:     ^~~~~ expected ';' after expression
        for( it = mBars.begin(); it += mBars.end(); it++ )
            it->Report();
        std::cout << "\n";
    }

int main( void )
{
    struct shm_remove
    {
         shm_remove() { bip::shared_memory_object::remove( "MySharedMemory" ); }
        ~shm_remove() { bip::shared_memory_object::remove( "MySharedMemory" ); }
    } remover;
    bip::managed_shared_memory   seg( bip::create_only, "MySharedMemory", 65536 );

    ShmemAllocator< void > shalloc( seg.get_segment_manager() );
    HeapAllocator<  void > halloc;

    HeapFoo  foo1( halloc  );
    ShmemFoo foo2( shalloc );
    foo1.Report();
    foo2.Report();  
}

解决方案

Ok, you've run into the Frequently Annoying Edgecase that template-template arguments aren't first class citizens in C++ (you cannot pass them around/typedef them):

What shall we do?

  1. allocator::rebind<T>

    Allocators have a rebind mechanism, I daresay precisely because of this. So you can pass a alloc<void> as if it is the open template, because you can always get from there to a sibling allocator type by doing Alloc::rebind<T>::other.

  2. Add to this the fact that allocators usually have conversion constructors that do this rebinding, you don't need to be overly specific in many places taking allocators

  3. in c++11, scoped_allocators have been introduced to avoid having to manually pass allocator instances in a number of places that will do internal construction of elements (e.g. emplace_back).

    There's library magic in place that will automatically add the allocator instance from the container's scoped_allocator as the last constructor argument (by default). Boost Container library has backported the scoped_allocator_adaptor concept to c++03 so you can use it.

Here's a full sample that shows you how to solve the issues you had, and also, how you can mix the heap-based Bar instances with the shared-memory Foo instance:

foo2.add(bar1); // this works because of ... MAGIC!

Which works due to the scoped_allocator mentioned above.

Live On Coliru

#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/container/scoped_allocator.hpp>

namespace bip = boost::interprocess;

namespace generic { 

    template <typename T, typename Alloc/* = std::allocator<T>*/ >
        using vector = bip::vector<T, typename Alloc::template rebind<T>::other >;

    template <typename Alloc> struct Bar {
        typedef Alloc allocator_type; // ties in with uses_allocator/scoped_allocator

        // only require allocator if not default-constructible
        Bar(Alloc alloc = Alloc()) : mInts(alloc) {}

        // conversion constructor so we can convert between allocators 
        template <typename OtherAlloc>
            Bar(Bar<OtherAlloc> const& rhs, Alloc alloc = Alloc())
                : mInts(rhs.mInts.begin(), rhs.mInts.end(), alloc) 
            {
            }

        void Report() const;

        void add(int i) { mInts.emplace_back(i); }

      private:
        template<typename OtherAlloc> friend struct Bar; // we can see each other's mInts
        typedef vector<int, Alloc> ints_t;
        ints_t mInts;
    };

    template <typename Alloc> struct Foo {
        typedef Alloc allocator_type; // ties in with uses_allocator/scoped_allocator

        Foo(Alloc alloc = Alloc()) : mBars(alloc) {}
        void Report() const;

        template <typename Bar>
        void add(Bar const& bar) { mBars.emplace_back(bar); }

      private:
        typedef vector<Bar<Alloc>, Alloc> mbars_t;
        mbars_t mBars;
    };
}

namespace heap {
    using VAlloc = std::allocator<void>;

    using Bar = generic::Bar<VAlloc>;
    using Foo = generic::Foo<VAlloc>;
}

namespace shared {
    using VAlloc = boost::container::scoped_allocator_adaptor<bip::allocator<void, bip::managed_shared_memory::segment_manager> >;

    using Bar = generic::Bar<VAlloc>;
    using Foo = generic::Foo<VAlloc>;
}

template <typename Alloc> void generic::Bar<Alloc>::Report() const {
    std::cout << "[";
    for (typename ints_t::const_iterator it = mInts.begin(); it != mInts.end(); it++)
        std::cout << (it == mInts.begin() ? "" : ", ") << *it;
    std::cout << "]\n";
}

template <typename Alloc>
void generic::Foo<Alloc>::Report() const {
    for (typename mbars_t::const_iterator it = mBars.begin(); it != mBars.end(); it++)
        it->Report();
    std::cout << "\n";
}

int main(void) {
    struct shm_remove {
        shm_remove()  { bip::shared_memory_object::remove("MySharedMemory"); }
        ~shm_remove() { bip::shared_memory_object::remove("MySharedMemory"); }
    } remover;

    ///////////////////////////////////
    // heap based:
    std::cout << "Heap based storage: \n";

    heap::Foo foo1;
    heap::Bar bar1;

    bar1.add(42);
    bar1.add(2);
    bar1.add(-99);

    foo1.add(bar1);
    foo1.Report();

    /////////////////////////////////
    std::cout << "Shared memory storage: \n";
    bip::managed_shared_memory seg(bip::create_only, "MySharedMemory", 65536);
    shared::VAlloc shalloc(seg.get_segment_manager());

    shared::Foo foo2(shalloc);
    shared::Bar bar2(shalloc);

    bar2.add(43);
    bar2.add(3);
    bar2.add(-98);

    foo2.add(bar2); // of course this works
    foo2.add(bar1); // this works because of ... MAGIC!
    foo2.Report();
}

Prints:

Heap based storage: 
[42, 2, -99]

Shared memory storage: 
[43, 3, -98]
[42, 2, -99]

这篇关于让进程间共享内存对象提振非共享副本::的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆