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).