This came to my attention today. I’m seeing an “AtomicFreeList” and an “AtomicQueue” in there. Both of which are multiple-reader and multiple-writer according to the comments in the code
I’d like to know; is there any reason why we’d still want NativeList and NativeQueue instead of these? Are there any caveats? And do they require any specific [DisableSafeties] when using them in jobs?
Atomics are faster than mutexes (mutexes are built on atomics) but they are not fast. From my limited understanding of x86, usage of atomics flush the store buffer (program order write queue) to the cache lines (roughly the penalty of a branch misprediction) and then the atomic could fail which leads to an actual branch prediction until it succeeds. During this process, none of the other threads can drain their store buffers. On top of this, once the atomic does hit cache, it then invalidates the cache line on all the other threads causing them to have to reload it. So when all the threads are off doing their own thing, an atomic operation is a little stall to the user thread and then all is well again. But when all the threads are trying to do atomics to the same memory, it becomes quite literally a memory traffic jam of epic proportions.
We had a discussion about the different containers and approaches to problems in this thread: ECS Culling
Long story short, NativeList, NativeQueue, NativeStream, and IJobParallelForFilter are all really good options compared to trying to get crazy with atomics. The containers in this new library are for very special cases (and even then I’m still suspicious).