Comments on "Applied Reading - Taming Shared Memory" by Josh Walker in Overload 51.
I really enjoyed to see an article about shared memory in Overload 51. For one, it (re-)promoted a solution for a frequent problem (managing common access to shared objects) that is generally much more appropriate than the usual solution "multi-threading". The overwhelming number of publications (books and articles) about multi-threading had the effect that most developers think that multithreading is the proper solution to the sharing problem (and even for problems that share virtually no resources). Therefore, it is really good to see an article about a long-known solution that is in my opinion nearly always more appropriate.
Then, I enjoyed the article because I'm now working for quite a while on a library to make the use of shared memory easier. Unfortunately, it turned out that using standard containers or strings inside of shared memory is virtually impossible. Not that there is a fundamental problem with containers in shared memory. Though it is not completely easy, it is possible to provide shm_ptr as a full blown pointer type (including pointer arithmetics). And providing a wrapper around shm_allocator that implements the STL allocator requirements is pretty easy. But unfortunately, the C++ standard gives library implementors the leeway to ignore the type Allocator::pointer and instead just assume that it is a raw pointer. And though the standard explicitely encourages library implementors not to use this leeway, I didn't yet come across an implementation that actually worked when Allocator::pointer was not a raw pointer. (Probably I just looked in the wrong places.)
What is really sad is that when I looked at the implementation, it seemed that there is no real reason for that, but just a general sloppiness by using " T* " instead of " Allocator::pointer ". (The main reason for this is probably historical as well as an unwillingness to really think about the requirements of " Allocator::pointer " and document them as an implementation defined enhancement.) So, to make shared memory really comfortable, you need to provide your own replacements for the standard containers and string. Or you ensure that the shared memory segment is mapped to the same address in all processes, but this is an option that is rarely available.
Some final notes: Whether shared memory is actually the proper solution for the problem at hand I'm not so sure. If only, because it's pretty hard to implement a clean and safe message queue. But then, if a different solution would have been chosen, we wouldn't have got this excellent article. And a minor issue with the presented code: Why is the size parameter of the shm_segment constructor of type " int ", while the return of get_size() and the internal size_ member are of type " unsigned int ". The proper type would probably be " size_t ".
Detlef Vollmann <firstname.lastname@example.org>
Response to Detlef Vollmann's comments
I found Detlef's comments on using standard containers in shared memory very interesting. It is unfortunate that current implementations fail to support this natural and useful extension. I hope this will change as libraries and compilers mature.
As I mentioned in the article, the choice of shared memory was influenced by my own skill set. It has so far proved an adequate solution, though I agree that it may not be the ideal one. Of course, it was also a useful topic for exposition.
As Detlef keenly points out, the shm_segment members and methods concerned with size should use size_t . The use of signed int is just sloppiness on my part. Finally, let me thank Detlef for his comments. I hope more readers will send their feedback on Overload articles.
Josh Walker email@example.com