Just allocate one shared-memory segment initially, and allocate more segments as needed. Programs only need to find this first segment to "rendezvous" with each other.
Devise your own logic,
e.g. a set of free-lists, for suballocating storage as required... perhaps ...
Code:
(struct whizboz *) alloc_whizboz() {
obtain_memory_mutex();
struct whizboz *result = remove_from_freelist(global->whizbozlist);
if (!result) result = carve_out_storage(sizeof(struct whizboz));
if (!result) {
get_another_segment();
result = carve_out_storage(sizeof(struct whizboz));
}
release_memory_mutex();
return result;
}
Both the size of the initial segment and the (default) size of subsequent segments should be program options.
A pointer may point from one segment to another segment without restriction.
If you have data-structures which are "logically" contiguous and flat, design them
(e.g. using C++ classes) so that they "physically" do not have to be. Thus you never have to "resize" anything. You may need to build trees or hash-tables or whatnot to enable you to efficiently locate a particular entry in this now-sparse data structure...