Noting that the push only touches the tail while the pop only touch head, thus these two operation will not interfere with each other when only one thread pushes and another pop.
We sacrifice the capacity of the queue by 1 to get this version of the circular queue to work, but the benefit is that there is no synchronization required for a single producer and single consumer thread. If we maintained a count, we would be forced to perform atomic updates on that variable to maintain the data structure
Here, the condition when the head of the queue and tail of the queue are same, the queue is said to be empty. This ensure that the push (working on tail) and pop (working on head) don't touch the same memory location simultaneously.
Shouldn't the q.data in the push function be a q->data, as data is a field in the q struct?
@Drizzle yes it should be q->data.
What does MOD_N(q->xx+x) actually do?
@POTUS I think it just returns (q->xx + x) mod N, I imagine there's a special declaration like this rather than using the usual % because x % N is a negative number if x is negative in a lot of programming languages (technically it corresponds to remainder rather than modulus).
Why is it important to assume a sequentially consistent memory system?