让进程间共享内存对象提振非共享副本:: [英] making non-shared copies of boost::interprocess shared memory objects
问题描述
我已经实现了设计在的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他们):
- ? 如何传送模板
我们该怎么办?
-
分配器::重新绑定< T>
分配器有一个绑定机制,我pcisely敢说,因为这个$ P $。所以,你可以通过一个
页头<无效>
,就好像它是开放的模板,因为你可以从那里通过做总是以同级分配器类型ALLOC ::重新绑定< T> ::其他
-
添加到这样一个事实,即分配器通常有转换构造函数,这样做重新绑定,你并不需要在很多地方采取分配器过于具体
-
在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:
- boost::interprocess Containers of containers NOT in shared memory
- boost::interprocess Containers of containers NOT in shared memory copy
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?
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 doingAlloc::rebind<T>::other
.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
in c++11,
scoped_allocator
s have been introduced to avoid having to manually passallocator
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 thescoped_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.
#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屋!