SOFe1970
u/SOFe1970
The semaphore example in the OP is a real world bug I found in someone's code many years ago (ok, I know they should have used a WaitGroup or an atomic int instead, but that's a different issue...). The fact that someone fell for it probably implies it is not "imagining things" and has actually caused misunderstanding.
This is an example where TOCTOU isn't a problem. If `len(ch) == 0`, there are no more receivers, and there are no senders at all, so `len(ch) == 0` is an eventual state. It will NOT transition to another state, so TOU (after TOC) will always have identical state as TOC.
The problem I demonstrated here is that TOU actually turns out to be before TOC (in terms of code order) due to CPU reordering memory accesses. And this is exactly what a global memory barrier is useful for, to ensure that TOC happens before TOU.