> What guarantees is shared supposed to provide? > > Shared means that multiple threads can access the data. The > guarantee is that if it is not shared, and not immutable, that > only the current thread can see it.
What if I have a thread that contains some shared data? Should the thread be created as shared, be cast to shared after construction or not be shared and fine grained shared applied to the respective shared data fields? > What does shared have to do with synchronization? > > Only shared data can be synchronized. It makes no sense to > synchronize thread local data. Define synchronized. With atomic ops on word size items this is clear, but what does it mean for aggregates? The language shows us no connection between synchronization and the shared data. What is one unit of data that is to be synchronized? > What does shared have to do with memory barriers? > > Reading/writing shared data emits memory barriers to ensure > sequential consistency (not implemented). That's exactly the problem. It assumes the unit is a word size item. If I have a Mutex to protect my unit of shared data, I don't need "volatile" handling of shared data. private shared class SomeThread : Thread { private: Condition m_condition; bool m_shutdown = false; ... } m_shutdown will be shared and it is shared data, but it is synchronized by the Mutex contained in that condition. Automatic memory barriers and such would only slow down execution. > What are the semantics of casting FROM unshared TO shared? > > Make sure there are no other unshared references to that same > data. > > What are the semantics of casting FROM shared TO > unshared? > > Make sure there are no other shared references to that same > data. That's just wrong to ask. `SomeThread` is a worker thread and data is passed to it regularly through a shared reference that is certainly never going away until the thread dies. Yet I must be able to "unshare" it's list of work items to process them. Now let's say I have an "empty" property. Shared or unshared? override @property bool empty() const { return m_list.empty; } It is only called internally by the thread itself after entering a certain critical section. I _know_ that m_list wont be accessible by other threads while .empty is running. But this seeming 1:1 relationship between entering "the" critical section and stripping shared is of course non-existent. Aggregates may contain Mutexes protecting different fields or even stacking on top of each other. So the text should read: > What are the semantics of casting FROM shared TO unshared? > > Make sure that during the period the data is unshared, no > other thread can modify those parts of it that you will be > accessing. If you don't use synchronization objects with > built-in memory-barriers like a Mutex, it is your > responsibility to properly synchronize data access through > e.g. atomicLoad/Store. That at least in general sanctifies casting away shared for the purpose of calling a method under protection of a user defined critical section. -- Marco