I want to add network control of a handful of parameters used by a service (daemon) running on a Linux embedded system. There's no need for procedure calls, each parameter can be polled in a very natural way. Shared memory seems a nice way to keep networking code out of the daemon, and limit shared access to a carefully controlled set of variables.
Since I don't want partial writes to cause visibility of values never written, I was thinking of using std::atomic<bool>
and std::atomic<int>
. However, I'm worried that std::atomic<T>
might be implemented in a way that only works with C++11 threads and not with multiple processes (potentially, not even with OS threads). Specifically, if the implementation uses any data structures stored outside the shared memory block, in a multi-process scenario this would fail.
I do see some requirements which suggest to be that std::atomic
won't hold an embedded lock object or pointer to additional data:
The atomic integral specializations and the specialization atomic<bool>
shall have standard layout. They shall each have a trivial default constructor and a trivial destructor. They shall each support aggregate initialization syntax.
There shall be pointer partial specializations of the atomic class template. These specializations shall have standard layout, trivial default constructors, and trivial destructors. They shall each support aggregate initialization syntax.
Trivial default construction and destruction seems to me to exclude associated per-object data, whether stored inside the object, via a pointer member variable, or via an external mapping.
However, I see nothing that excludes an implementation from using a single global mutex / critical section (or even a global collection, as long as the collection elements aren't associated with individual atomic objects -- something along the lines of a cache association scheme could be used to reduce false conflicts). Obviously, access from multiple processes would fail on an implementation using a global mutex, because the users would have independent mutexes and not actually synchronize with each other.
Is an implementation of atomic<T>
allowed to do things that are incompatible with inter-process shared memory, or are there other rules that make it safe?
I just noticed that trivial default construction leaves the object in a not-ready state, and a call to atomic_init
is required. And the Standard mentions initialization of locks. If these are stored inside the object (and dynamic memory allocation seems impossible, since the destructor remains trivial) then they would be shared between processes. But I'm still concerned about the possibility of a global mutex.
In any case, guaranteeing a single call to atomic_init
for each variable in a shared region seems difficult... so I suppose I'll have to steer away from the C++11 atomic types.
See Question&Answers more detail:
os