How to store stl objects in shared memory (C++)? - c++

I've the following code pattern:
class A {
double a, b, c;
...
};
class B {
map<int, A> table; // Can have maximum of MAX_ROWS elements.
...
};
class C {
B entries;
queue<int> d;
queue<int> e;
...
};
Now I want to store an object of type C in a shared memory, so that different processes can append, update and read it. How can I do this? (Note: I know how to store a simple C array that has a fixed size in shared memory. Also, remember that B.table may have arbitrary entries.

Use boost::interprocess, this library exposes this functionality.
EDIT: Here are some changes you'll need to do:
The example already defines an allocator that will allocate from the shared memory block, you need to pass this to the map and the queue. This means you'll have to change your definitions:
class B
{
map<int, A, less<int>, MapShmemAllocator> table;
// Constructor of the map needs the instance of the allocator
B(MapShmemAllocator& alloc) : table(less<int>(), alloc)
{ }
}
For queue, this is slightly complicated, because of the fact that it's really just an adapter, so you need to pass in the real implementation class as a template parameter:
typedef queue<int, deque<int, QueueShmemAllocator> > QueueType;
Now your class C changes slightly:
class C
{
B entries;
QueueType d, e;
C(MapShmemAllocator& allocM, QueueShmemAllocator& allocQ) : entries(allocM), d(allocQ), e(allocQ)
{ }
}
Now from the segment manager, construct an instance of C with the allocator.
C *pC = segment.construct<C>("CInst")(allocM_inst, allocQ_inst);
I think that should do the trick. NOTE: You will need to provide two allocators (one for queue and one for map), not sure if you can construct two allocators from the same segment manager, but I don't see why not.

Building and using STL objects in shared memory is not tricky yet (especially using boost::interprocess wrappers). For sure you should also use syncing mechanisms (also not a problem with boost's named_mutex).
The real challenge is to keep consistency of STL objects in a shared memory. Basically, if one of the processes crashes in a bad point in time, it leaves other processes with a two big problems:
A locked mutex (can be resolved using tricky PID-to-mutex mappings, robust mutexes (wherever available), timed mutexes etc.
An STL object in the inconsistent state (e.g. semi-updated map structure during erase() procedure). In general, this is not recoverable yet, you need to destroy and re-construct object in a shared memory region from the scratch (probably killing all other processes as well). You may try to intercept all possible external signals in your app and crossing fingers hope everything will go well and process never fail in a bad moment.
Just keep this in mind when deciding to use shared memory in your system.
UPD: check shmaps (https://github.com/rayrapetyan/shmaps) project to get an idea of how things should work.

This can be tricky. For starters, you'll need a custom allocator: Boost
Interprocess has one, and I'd start with it. In your exact example,
this may be sufficient, but more generally, you'll need to ensure that
all subtypes also use the shared memory. Thus, if you want to map from
a string, that string will also need a custom allocator, which means
that it has a different type than std::string, and you can't copy or
assign to it from an std::string (but you can use the two iterator
constructor, e.g.:
typedef std::basic_string<char, std::char_traits<char>, ShmemAllocator> ShmemString;
std::map<ShmemString, X, std::less<ShmemString>, ShmemAllocator> shmemMap;
with accesses like:
shmemMap[ShmemString(key.begin(), key.end())] ...
And of course, any types you define which go into the map must also use
shared memory for any allocations: Boost Interprocess has an
offset_ptr which may help here.

Related

Dynamically constructing objects in an area that can be discarded all at once

For building a cache-like data structure, I would like to do the following:
I would like to have a class Cache building and managing some data structure in some area of memory of a predefined size.
For building the data structure, the Cache class should be able to use standard classes like, e.g., vector. Now all objects dynamically allocated by the Cache class (directly or indirectly) should go into the predefined area in memory, which I would like to be able to discard all at once (i.e. without destructing each individual object) by simply zeroing it (or forgetting about it). I know that this is against the standard.
I thought of the following approach:
alter_operator_new_to_allocate_everything_within_my_cache_area ();
cache.cacheMyObjects (...);
alter_operator_new_into_normal_behaviour ();
Questions:
Is such an approach, or a solution to a similar problem, described
anywhere?
Will that work?
Or is there a better solution to my problem?
Of course, I could as well try to write the cache class from scratch such that is uses only POD data structures, but that would mean reinventing the wheel in many cases.
I only need a solution that works for VS2013/2015 and Windows.
I believe the problem you are trying to solve can be done with a custom allocator.
You can preallocate the large chunk of contiguous memory you will need for the cache. You can then define a custom allocator object to always allocate from that block of memory. Then pass that allocator object to std::vector or any other data structure [see http://www.cplusplus.com/reference/vector/vector/, second template parameter].
Your allocator class must implement the members declared in allocator_traits: http://en.cppreference.com/w/cpp/memory/allocator_traits
Example:
class my_allocator {
void* memory_block;
my_allocator() { memory_block = malloc( ... ); }
~my_allocator() { free(memory_block); }
void* allocate(..) { ..assign from memory_block.. }
};
class Cache {
my_allocator my_alloc;
std::vector< int, my_alloc > my_vector;
..other data..
};
Henceforth, your vector will always assign from the memory_block. If you do this with all your data structures in Cache, it will always use the same contiguous memory.
(I've not compiled the code, so there might be somewhat different semantics)

Non-Boost STL allocator for inter-process shared memory?

Due to policy where I work, I am unable to use a version of Boost newer than 1.33.1 and unable to use a version of GCC newer than 4.1.2. Yes, it's garbage, but there is nothing I can do about it. Boost 1.33.1 does not contain the interprocess library.
That said, one of my projects requires placing an std::map (or more likely an std::unordered_map) in to shared memory. It is only written/modified ONE TIME when the process loads by a single process (the "server") and read by numerous other processes. I haven't done shared memory IPC before so this is fairly new territory for me. I took a look at shmget() but it would appear that I can't continually use the same shared memory key for allocation (as I assume would be needed with STL container allocators).
Are there any other NON-BOOST STL allocators that use shared memory?
EDIT: This has been done before. Dr. Dobbs had an article on how to do this exactly back in 2003, and I started to use it as a reference. However, the code listings are incomplete and links to them redirect to the main site.
EDIT EDIT: The only reason I don't just re-write Boost.Interprocess is because of the amount of code involved. I was just wondering if there was something relatively short and concise specifically for POSIX shared memory that I could re-write from scratch since data transfers between networks are also subject to a multi-day approval process...
Pointers do not work in shared memory unless you cannot pin down the shared memory at a fixed address (consistent in all processes). As such, you need specific classes that will either be contiguous (no pointer), or have an offset (and not a pointer) into the memory area in which the shared memory is mapped.
We are using shared memory at work in a pretty similar situation: one process computes a set of data, places it in shared memory, and then signal the other processes that they may map the memory into their own address space; the memory is never changed afterwards.
The way we go about it is having POD structures (*) (some including char xxx[N]; attributes for string storage). If you can actually limit your strings, you are golden. And as far as map goes: it's inefficient for read-only storage => a sorted array performs better (hurray for memory locality). So I would advise going at it so:
struct Key {
enum { Size = 318 };
char value[Size];
};
struct Value {
enum { Size = 412 };
enum K { Int, Long, String };
K kind;
union { int i; long l; char string[Size]; } value;
};
And then simply have an array of std::pair<Key, Value> that you sort (std::sort) and over which you use std::lower_bound for searches. You'll need to write a comparison operator for key, obviously:
bool operator<(Key const& left, Key const& right) {
return memcmp(left.value, right.value, Key::Size) < 0;
}
And I agree that the enum + union trick is less appealing (interface wise) than a boost variant... it's up to you to make the interface better.
(*) Actually, a pure POD is not necessary. It's perfectly okay to have private attributes, constructors and copy constructors for example. All that is needed is to avoid indirection (pointers).
Simple workaround. Create your own "libNotBoost v1.0` from Boost 1.51. The Boost library allows this. Since it's no longer Boost, you're fine.

shared_ptr with vector

I currently have vectors such as:
vector<MyClass*> MyVector;
and I access using
MyVector[i]->MyClass_Function();
I would like to make use of shared_ptr. Does this mean all I have to do is change my vector to:
typedef shared_ptr<MyClass*> safe_myclass
vector<safe_myclass>
and I can continue using the rest of my code as it was before?
vector<shared_ptr<MyClass>> MyVector; should be OK.
But if the instances of MyClass are not shared outside the vector, and you use a modern C++11 compiler, vector<unique_ptr<MyClass>> is more efficient than shared_ptr (because unique_ptr doesn't have the ref count overhead of shared_ptr).
Probably just std::vector<MyClass>. Are you
working with polymorphic classes or
can't afford copy constructors or have a reason you can't copy and are sure this step doesn't get written out by the compiler?
If so then shared pointers are the way to go, but often people use this paradigm when it doesn't benefit them at all.
To be complete if you do change to std::vector<MyClass> you may have some ugly maintenance to do if your code later becomes polymorphic, but ideally all the change you would need is to change your typedef.
Along that point, it may make sense to wrap your entire std::vector.
class MyClassCollection {
private : std::vector<MyClass> collection;
public : MyClass& at(int idx);
//...
};
So you can safely swap out not only the shared pointer but the entire vector. Trade-off is harder to input to APIs that expect a vector, but those are ill-designed as they should work with iterators which you can provide for your class.
Likely this is too much work for your app (although it would be prudent if it's going to be exposed in a library facing clients) but these are valid considerations.
Don't immediately jump to shared pointers. You might be better suited with a simple pointer container if you need to avoid copying objects.

Is it unefficient to use a std::vector when it only contains two elements?

I am building a C++ class A that needs to contain a bunch of pointers to other objects B.
In order to make the class as general as possible, I am using a std::vector<B*> inside this class. This way any number of different B can be held in A (there are no restrictions on how many there can be).
Now this might be a bit of overkill because most of the time, I will be using objects of type A that only hold either 2 or 4 B*'s in the vector.
Since there is going to be a lot of iterative calculations going on, involving objects of class A, I was wondering if there is a lot of overhead involved in using a vector of B's when there are only two B's needed.
Should I overload the class to use another container when there are less than 3 B present?
to make things clearer: A are multipoles and B are magnetic coils, that constitute the multipoles
Premature optimization. Get it working first. If you profile your application and see that you need more efficiency (in memory or performance), then you can change it. Otherwise, it's a potential waste of time.
I would use a vector for now, but typedef a name for it instead of spelling std::vector out directly where it's used:
typedef std::vector vec_type;
class A {
vec_type<B*> whatever;
};
Then, when/if it becomes a problem, you can change that typedef name to refer to a vector-like class that's optimized for a small number of contained objects (e.g., does something like the small-string optimization that's common with many implementations of std::string).
Another possibility (though I don't like it quite as well) is to continue to use the name "vector" directly, but use a using declaration to specify what vector to use:
class A {
using std::vector;
vector<B*> whatever;
};
In this case, when/if necessary, you put your replacement vector into a namespace, and change the using declaration to point to that instead:
class A {
using my_optimized_version::vector;
// the rest of the code remains unchanged:
vector<B*> whatever;
};
As far as how to implement the optimized class, the typical way is something like this:
template <class T>
class pseudo_vector {
T small_data[5];
T *data;
size_t size;
size_t allocated;
public:
// ...
};
Then, if you have 5 or fewer items to store, you put them in small_data. When/if your vector contains more items than that fixed limit, you allocate space on the heap, and use data to point to it.
Depending a bit on what you're trying to optimize, you may want to use an abstract base class, with two descendants, one for small vectors and the other for large vectors, with a pimpl-like class to wrap them and make either one act like something you can use directly.
Yet another possibility that can be useful for some situations is to continue to use std::vector, but provide a custom Allocator object for it to use when obtaining storage space. Googling for "small object allocator" should turn up a number of candidates that have already been written. Depending on the situation, you may want to use one of those directly, or you may want to use them as inspiration to write your own.
If you need an array of B* that will never change its size, you won't need the dynamic shrinking and growing abilities of the std::vector.
So, probably not for reasons of efficiency, but for reasons of intuition, you could consider using a fixed length array:
struct A {
enum { ndims = 2 };
B* b[ndims];
};
or std::array (if available):
struct A {
std::array<B*, 2> b;
};
see also this answer on that topic.
Vectors are pretty lean as far as overhead goes. I'm sure someone here can give more detailed information about what that really means. But if you've got performance issues, they're not going to come from vector.
In addition I'd definitely avoid the tactic of using different containers depending on how many items there are. That's just begging for a disaster and won't really give you anything in return.

How to find the memory used by any object

class Help
{
public:
Help();
~Help();
typedef std::set<string> Terms;
typedef std::map<string, std::pair<int,Terms> > TermMap;
typedef std::multimap<int, string, greater<int> > TermsMap;
private:
TermMap terms;
TermsMap termsMap;
};
How can we find the memory used (in bytes) by the objects term and termsMap. Do we have any library ?
If you are looking for the full memory usage of an object, this can't be solved in general in C++ - while we can get the size of an instance itself via sizeof(), the object can always allocate memory dynamically as needed.
If you can find out how big the individual element in a container are, you can get a lower bound:
size = sizeof(map<type>) + sum_of_element_sizes;
Keep in mind though that the containers can still allocate additional memory as an implementation detail and that for containers like vector and string you have to check for the allocated size.
How can we find the memory used (in
bytes) by the objects term and
termsMap. Do we have any library ?
You should use your own allocator type.
typedef std::set<string,
your_allocator_1_that_can_count_memory_consumption_t> Terms;
typedef std::map<string, std::pair<int,Terms>,
your_allocator_2_that_can_count_memory_consumption_t> TermMap;
typedef std::multimap<int, string, greater<int>,
your_allocator_3_that_can_count_memory_consumption_t> TermsMap;
I have not yet checked this idea for std::string so if it is difficult to implement just use your own class fixed_string which just wraps char s[max-string-lenght].
And when you need in your program to find out memory consumption just get it from your_allocator_1_that_can_counts_memory_consumption_t, your_allocator_2_that_can_counts_memory_consumption_t,
your_allocator_3_that_can_counts_memory_consumption_t.
Edited
For UncleBens I want to clarify my point.
As far as I understand the question of the ARV it is necessary to know how much memory is allocated for set::set and std::map including all memory allocated for elements of the set and the map. So it is not just sizeof(terms).
So I just suggested a very simple allocator. Without going into too much details it might look like this:
template <class T>
class your_allocator_1_that_can_counts_memory_consumption_t {
public:
// interfaces that are required by the standart
private:
std::allocator<T> std_allocator_;
// here you need to put your variable to count bytes
size_t globale_variable_for_allocator_1_to_count_bytes_;
};
This allocator just counts number of allocated and deallocated bytes and for real allocation and deallocation use its member std_allocator_. I might need to debug it under gdb in order to set a breakpoint on malloc() and on free() to make sure that every allocation and deallocation actually goes through my allocator.
I would be grateful if you point me at some problems with this idea since I have already implemented it in my program that runs on Windows, Linux and HP-UX and I simply asks my allocators in order to find how much memory each of my containers use.
Short Answer: No
Long Answer:
-> The basic object yes. sizeof(<TYPE>) but this is only useful for limited things.
-> A container and its contained members: NO
If you make assumptions about the structures used to implement these objects you can estimate it. But even that is not really useful ( apart from the very specific case of the vector).
The designers of the STL deliberately did not define the data structures that should be used by these containers. There are several reasons for this, but one of them (in my opinion) is to stop people making assumptions about the internals and thus try and do silly things that are not encapsulated by the interface.
So the question then comes down to why do you need to know the size?
Do you really need to know the size (unlikely but possible).
Or is there a task you are trying to achieve where you think you need the size?
If you're looking for the actual block of memory, the numerical value of a pointer to it should be it. (Then just add the number of bytes, and you have the end of the block).
the sizeof() operator ought to do it:
size_t bytes = sizeof(Help::TermMap);