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.
Related
I have set up the AVR compiler for using with an Atmel microcontroller using this guide.
I don't have access to strings, vectors etc. How can this be added?
The quick answer is that they are not available and you need to write your own wrapper classes to get this sort of functionality.
If you want to use c++ for the embedded platform you won't have access to all of the standard library. Importantly though, you don't want all of the standard library as it's too heavyweight for some embedded projects. Some language features (like exception handling) might not be possible on the platform you are choosing or might be too expensive given the resources available to you. The lack of some language features makes it impossible to implement certain standard containers, for example the containers that can throw exceptions might not be able to be implemented in a standards-conforming way on some platforms. Additionally there's some c++ constructs that might be available but would be a bad idea to use on the embedded platform. Dynamic allocation of memory via new and delete will very likely run you into a significant number of problems as you don't have a lot of memory and issues such as memory fragmentation are very difficult to deal with. (you would probably want to look into placement new along with some other memory allocation scheme to avoid some of these issues if you needed dynamic memory for some reason)
If you want to have the benefits of containers like std::array and std::string you will need to write your own memory management classes. One of the main benefits of using the std containers is the way in which they greatly simplify your memory management (compared with using raw C-style-arrays). If you are doing a large embedded c++ project you can write your own wrappers for the memory management using RAII and other basic c++ language constructs. For the most part you need to avoid dynamic memory allocation and exception handling when making these classes.
One of the things I find has a good ROI is making some structs/classes that wrap an array along with the length of the array. By keeping the sizes connected you can keep your code a lot clearer. Frequently I find myself writing something like this:
template<typename T, uint8_t MAX_SIZE>
class array_helper{
public:
typedef T value_type;
array_wrapper():
m_data()
{}
T& operator[](unsigned int idx){
return m_data[idx];
}
T* data(){
return this->m_data;
}
const uint8_t s_max_size = MAX_SIZE;
private:
T m_data[MAX_SIZE];
};
You would want to expand on this to do what you need, but hopefully this gives you an idea.
do not do this.
using dynamic memory allocation on avr is not recommendable, since it has not a MMU and only very limited RAM and dynamic memory allocation requires some overhead for bookkeeping.
also there is the danger of memory fragmentation.
on such tiny processors you should only use static and autmatic fixed size memory buffers.
that ensures deterministic run time behavior.
If i have this code :
#include <assert.h>
class Foo {
public:
bool is_static();
bool is_stack();
bool is_dynamic();
};
Foo a;
int main()
{
Foo b;
Foo* c = new Foo;
assert( a.is_static() && !a.is_stack() && !a.is_dynamic());
assert(!b.is_static() && b.is_stack() && !b.is_dynamic());
assert(!c->is_static() && !c->is_stack() && c->is_dynamic());
delete c;
}
Is it possible to implement is_stack, is_static, is_dynamic method to do so in order to be assertions fulfilled?
Example of use: counting size of memory which particular objects of type Foo uses on stack, but not counting static or dynamic memory
This cannot be done using standard C++ facilities, which take pains to ensure that objects work the same way no matter how they are allocated.
You can do it, however, by asking the OS about your process memory map, and figuring out what address range a given object falls into. (Be sure to use uintptr_t for arithmetic while doing this.)
Scroll down to the second answer that gives a wide array of available options depending on the Operating System:
How to determine CPU and memory consumption from inside a process?
I would also recommend reading this article on Tracking Memory Alloactions in C++:
http://www.almostinfinite.com/memtrack.html
Just be aware that it's a ton of work.
while the intention is good here, the approach is not the best.
Consider a few things:
on the stack you allocate temporary variables for your methods. You
don't always have to worry about how much stack you use because the
lifetime of the temp variables is short
related to stack what you usually care about is not corrupting it,
which can happen if your program uses pointers and accesses data
outside the intended bounds. For this type of problems a isStatic
function will not help.
for dynamic memory allocation you usually override the new/ delete
operators and keep a counter to track the amount of memory used. so
again, a isDynamic function might not do the trick.
in the case of global variables (you said static but I extended the
scope a bit) which are allocated in a separate data section (not
stack nor heap) well you don't always care about them because they
are statically allocated and the linker will tell you at link time if
you don't have enough space. Plus you can check the map file if you
really want to know address ranges.
So most of your concerns are solved at compile time and to be honest you rarely care about them. And the rest are (dynamic memory allocation) are treated differently.
But if you insist on having those methods you can tell the linker to generate a map file which will give you the address ranges for all data sections and use those for your purposes.
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.
Pointers cannot be persisted directly to file, because they point to absolute addresses. To address this issue I wrote a relative_ptr template that holds an offset instead of an absolute address.
Based on the fact that only trivially copyable types can be safely copied bit-by-bit, I made the assumption that this type needed to be trivially copyable to be safely persisted in a memory-mapped file and retrieved later on.
This restriction turned out to be a bit problematic, because the compiler generated copy constructor does not behave in a meaningful way. I found nothing that forbid me from defaulting the copy constructor and making it private, so I made it private to avoid accidental copies that would lead to undefined behaviour.
Later on, I found boost::interprocess::offset_ptr whose creation was driven by the same needs. However, it turns out that offset_ptr is not trivially copyable because it implements its own custom copy constructor.
Is my assumption that the smart pointer needs to be trivially copyable to be persisted safely wrong?
If there's no such restriction, I wonder if I can safely do the following as well. If not, exactly what are the requirements a type must fulfill to be usable in the scenario I described above?
struct base {
int x;
virtual void f() = 0;
virtual ~base() {} // virtual members!
};
struct derived : virtual base {
int x;
void f() { std::cout << x; }
};
using namespace boost::interprocess;
void persist() {
file_mapping file("blah");
mapped_region region(file, read_write, 128, sizeof(derived));
// create object on a memory-mapped file
derived* d = new (region.get_address()) derived();
d.x = 42;
d->f();
region.flush();
}
void retrieve() {
file_mapping file("blah");
mapped_region region(file, read_write, 128, sizeof(derived));
derived* d = region.get_address();
d->f();
}
int main() {
persist();
retrieve();
}
Thanks to all those that provided alternatives. It's unlikely that I will be using something else any time soon, because as I explained, I already have a working solution. And as you can see from the use of question marks above, I'm really interested in knowing why Boost can get away without a trivially copyable type, and how far can you go with it: it's quite obvious that classes with virtual members will not work, but where do you draw the line?
To avoid confusion let me restate the problem.
You want to create an object in mapped memory in such a way that after the application is closed and reopened the file can be mapped once again and object used without further deserialization.
POD is kind of a red herring for what you are trying to do. You don't need to be binary copyable (what POD means); you need to be address-independent.
Address-independence requires you to:
avoid all absolute pointers.
only use offset pointers to addresses within the mapped memory.
There are a few correlaries that follow from these rules.
You can't use virtual anything. C++ virtual functions are implemented with a hidden vtable pointer in the class instance. The vtable pointer is an absolute pointer over which you don't have any control.
You need to be very careful about the other C++ objects your address-independent objects use. Basically everything in the standard library may break if you use them. Even if they don't use new they may use virtual functions internally, or just store the address of a pointer.
You can't store references in the address-independent objects. Reference members are just syntactic sugar over absolute pointers.
Inheritance is still possible but of limited usefulness since virtual is outlawed.
Any and all constructors / destructors are fine as long as the above rules are followed.
Even Boost.Interprocess isn't a perfect fit for what you're trying to do. Boost.Interprocess also needs to manage shared access to the objects, whereas you can assume that you're only one messing with the memory.
In the end it may be simpler / saner to just use Google Protobufs and conventional serialization.
Yes, but for reasons other than the ones that seem to concern you.
You've got virtual functions and a virtual base class. These lead to a host of pointers created behind your back by the compiler. You can't turn them into offsets or anything else.
If you want to do this style of persistence, you need to eschew 'virtual'. After that, it's all a matter of the semantics. Really, just pretend you were doing this in C.
Even PoD has pitfalls if you are interested in interoperating across different systems or across time.
You might look at Google Protocol Buffers for a way to do this in a portable fashion.
Not as much an answer as a comment that grew too big:
I think it's going to depend on how much safety you're willing to trade for speed/ease of usage. In the case where you have a struct like this:
struct S { char c; double d; };
You have to consider padding and the fact that some architectures might not allow you to access a double unless it is aligned on a proper memory address. Adding accessor functions and fixing the padding tackles this and the structure is still memcpy-able, but now we're entering territory where we're not really gaining much of a benefit from using a memory mapped file.
Since it seems like you'll only be using this locally and in a fixed setup, relaxing the requirements a little seems OK, so we're back to using the above struct normally. Now does the function have to be trivially copyable? I don't necessarily think so, consider this (probably broken) class:
1 #include <iostream>
2 #include <utility>
3
4 enum Endian { LittleEndian, BigEndian };
5 template<typename T, Endian e> struct PV {
6 union {
7 unsigned char b[sizeof(T)];
8 T x;
9 } val;
10
11 template<Endian oe> PV& operator=(const PV<T,oe>& rhs) {
12 val.x = rhs.val.x;
13 if (e != oe) {
14 for(size_t b = 0; b < sizeof(T) / 2; b++) {
15 std::swap(val.b[sizeof(T)-1-b], val.b[b]);
16 }
17 }
18 return *this;
19 }
20 };
It's not trivially copyable and you can't just use memcpy to move it around in general, but I don't see anything immediately wrong with using a class like this in the context of a memory mapped file (especially not if the file matches the native byte order).
Update:
Where do you draw the line?
I think a decent rule of thumb is: if the equivalent C code is acceptable and C++ is just being used as a convenience, to enforce type-safety, or proper access it should be fine.
That would make boost::interprocess::offset_ptr OK since it's just a helpful wrapper around a ptrdiff_t with special semantic rules. In the same vein struct PV above would be OK as it's just meant to byte swap automatically, though like in C you have to be careful to keep track of the byte order and assume that the structure can be trivially copied. Virtual functions wouldn't be OK as the C equivalent, function pointers in the structure, wouldn't work. However something like the following (untested) code would again be OK:
struct Foo {
unsigned char obj_type;
void vfunc1(int arg0) { vtables[obj_type].vfunc1(this, arg0); }
};
That is not going to work. Your class Derived is not a POD, therefore it depends on the compiler how it compiles your code. In another words - do not do it.
by the way, where are you releasing your objects? I see are creaing in-place your objects, but you are not calling destructor.
Absolutely not. Serialisation is a well established functionality that is used in numerous of situations, and certainly does not require PODs. What it does require is that you specify a well defined serialisation binary interface (SBI).
Serialisation is needed anytime your objects leave the runtime environment, including shared memory, pipes, sockets, files, and many other persistence and communication mechanisms.
Where PODs help is where you know you are not leaving the processor architecture. If you will never be changing versions between writers of the object (serialisers) and readers (deserialisers) and you have no need for dynamically-sized data, then PODs allow easy memcpy based serialisers.
Commonly, though, you need to store things like strings. Then, you need a way to store and retrieve the dynamic information. Sometimes, 0 terminated strings are used, but that is pretty specific to strings, and doesn't work for vectors, maps, arrays, lists, etc. You will often see strings and other dynamic elements serialized as [size][element 1][element 2]… this is the Pascal array format. Additionally, when dealing with cross machine communications, the SBI must define integral formats to deal with potential endianness issues.
Now, pointers are usually implemented by IDs, not offsets. Each object that needs to be serialise can be given an incrementing number as an ID, and that can be the first field in the SBI. The reason you usually don't use offsets is because you may not be able to easily calculate future offsets without going through a sizing step or a second pass. IDs can be calculated inside the serialisation routine on first pass.
Additional ways to serialize include text based serialisers using some syntax like XML or JSON. These are parsed using standard textual tools that are used to reconstruct the object. These keep the SBI simple at the cost of pessimising performance and bandwidth.
In the end, you typically build an architecture where you build serialisation streams that take your objects and translate them member by member to the format of your SBI. In the case of shared memory, it typically pushes the members directly on to the memory after acquiring the shared mutex.
This often looks like
void MyClass::Serialise(SerialisationStream & stream)
{
stream & member1;
stream & member2;
stream & member3;
// ...
}
where the & operator is overloaded for your different types. You may take a look at boost.serialize for more examples.
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);