The rule is the same as other multithreaded languages without a multithreading-aware GC:
_Ensure the lifetime of whatever you [access](https://forum.nim-lang.org/postActivity.xml#access) >From this you can derive a couple rules: * Stack objects can be accessed only if allocated in the current thread or an ancestor thread that survives the current thread. * Heap objects can only be accessed until they are collected. * Similar to stack: ref objects can be used if, thanks to blocking/awaiting there is a guarantee that the multithreaded section ends before ref object is collected by the ancestor thread. * Or manual alloc/free should be used * Or you use atomic refcounting: <https://github.com/nim-lang/threading/blob/49562fa0/threading/smartptrs.nim#L77-L132> Now the old and the new memory management (deferred refcounting vs arc - automatic refcounting) does not change those **accessing** principles but significantly improve **sharing**. In many cases it is significantly more efficient, maintainable and debuggable to have an unique owner of an object or data and dispatch all transformation steps of this object to several procs or services. Those may or may not be on separate threads. This is called a producer/consumer architecture (or actor model in some case or microservice if done at whole machine scale for some reason) The main advantages are: * within that proc or service, everything is single threaded and can be coded as usual. * no thread contention * backpressure-handling via queues at the input and output of those services * spinning up more threads with a copy of the proc/service can help deal with full queues However, there is no more notion of ancestor thread that can wait for its child thread to stop processing. What's the issue? you need to pass the data from one thread to the other. Actually you don't have to do this, you can be much faster by passing "ownership" so the pointer (handle) to the data. Still if behind there is some GC-ed memory, it needs to be collected once done and no ancestor thread can be relied on. Hence in the old memory management model: * either it needed to somehow be returned to the original thread as only it was able to collect the GC-ed data. * or data needed to be deep-copied in queues, possibly twice: Producer -> channel -> consumer This is not the case anymore with ARC (or Boehm or if the data doesn't use GC-ed memory)