Thanks Araq for the link, it is very intersting. It is also not too difficult to create oneself a linkedlist that should work with ARC. For example : ## Source chatgpt for 30% import threading/smartptrs import std/atomics proc newAtomic*[T](val: sink T): Atomic[T] = result.store(val) type Node[T] = object val: T next: Atomic[ptr Node[T]] ThreadQueueObj[T] = object head: Atomic[ptr Node[T]] tail: Atomic[ptr Node[T]] ThreadQueue*[T] = SharedPtr[ThreadQueueObj[T]] proc `=destroy`*[T](q: ThreadQueueObj[T]) {.nodestroy.} = let qAddr = addr q var currentNode = qAddr[].head.load() while currentNode != nil: let nextNode = currentNode.next.load() `=destroy`(currentNode.val) deallocShared(currentNode) currentNode = nextNode proc newThreadQueue*[T](): ThreadQueue[T] = let node = cast[ptr Node[T]](alloc0(sizeof Node[T])) var atomicNode = newAtomic(node) return newSharedPtr(ThreadQueueObj[T]( head: atomicNode, tail: atomicNode )) proc addLast*[T](q: ThreadQueue[T], val: sink T) = var newNode = cast[ptr Node[T]](alloc(sizeof Node[T])) newNode[] = Node[T]( val: val, next: newAtomic[ptr Node[T]](nil), ) let prevTail = q[].tail.exchange(newNode) prevTail[].next.store(newNode) proc popFirst*[T](q: ThreadQueue[T], outVal: out T): bool = var oldHead = q[].head.load() let newHead = oldHead[].next.load() if newHead == nil: return false if q[].head.compareExchange(oldHead, newHead): outVal = newHead[].val deallocShared(oldHead) return true proc empty*[T](q: ThreadQueue[T]): bool = ## The atomicity cannot be guaranted return q[].head.load() == q[].tail.load() var l = newThreadQueue[int]() for i in 1..1_000_000: l.addLast(i) Run
However, std/channels is faster, provides non busy sleep, and is surely more memory efficient