On 30/07/2014 20:35, Klaim - Joël Lamotte wrote:
A really simple (albeit heavy-handed) way of doing this lock-free (or almost lock-free, depending on shared_ptr implementation) is to have your data in a shared_ptr; whenever something wants to act on the data it uses atomic_load to fetch it from some well-known location and can then do whatever read-only access it wishes; when it wants to change the data it first copies the entire object, makes the changes in the copy, and then uses atomic_compare_exchange to replace the "real" version. If the compare fails, it lost the race to a faster writer so must perform its updates again on the new data and try exchanging again.
This would work I guess but not well with big values (like a big struct). Also, from my understanding, having one "copy" of the object for each subscriber seems to be potentially more efficient if you already know that each subscriber work with it's own thread (or set of threads).
Copies are not efficient for a big struct, but copies only occur on write so it's not a big deal if writes are rare. Having a separate copy for each subscriber is helpful to avoid write contention, but if everything is only reading from a single shared object that is seldom written to then I don't think it provides any benefit (but I'm not an expert on cache effects). My gut feeling is that which approach is "better" depends on the number of subscribers and the frequency of actions. You do pay a bit for an atomic load/exchange (it's not a lot, but it's still something you want to avoid doing in a tight loop), but it means you only need to copy once; conversely having copies for each subscriber lets you avoid the atomics but requires you to make N copies. There are other tradeoffs as well, of course -- the one I proposed above doesn't have notifications on change, it just lets existing operations continue using the old data while new operations silently pick up the new data (basically a pull model); while a push model explicitly notifies subscribers that new data is available and lets them potentially do something esoteric if required -- but if implemented naively may result in the subscribers all being called from the publisher's thread, which may introduce contention and cache fragmentation.