This is probably simplistic, but in my safe, toy assembly language for teaching programming I simply avoid ever sharing (always refcounted) pointers between threads. Instead it pervasively uses channels for communication, and while channels are generic anything you put in them gets deep-copied on write. The deep copy is smart enough to preserve cycles, so say if you send in a linked list that contains a cycle the reader will see a linked list with an identical topology. It will just be <i>utterly</i> disjoint with the original linked list.<p>These design decisions allow me to provide safe pointer access and avoid all race conditions while teaching programming and concurrency, but they probably incur significant performance loss on certain programs. My hope is that the design constraints they impose on the programmer aren't insurmountable. We'll see.<p>(More info on the project: <a href="https://github.com/akkartik/mu#readme" rel="nofollow">https://github.com/akkartik/mu#readme</a>. On its memory model: <a href="https://news.ycombinator.com/item?id=11855470" rel="nofollow">https://news.ycombinator.com/item?id=11855470</a>. On the deep-copy implementation: <a href="https://github.com/akkartik/mu/blob/07ab3e3f35/073deep_copy.cc#L243" rel="nofollow">https://github.com/akkartik/mu/blob/07ab3e3f35/073deep_copy....</a>)