I'm trying to program a simple parallel processing system which should generate N objects to put in a container in a multi-threaded environment.
To tell the threads when to stop generating the object I created a simple reverse counter that starts at N at run down at 0 with each thread decrementing it in parallel. The counter is supposed to be a uint64_t and I wanted to try the atomic support of C++11. The code looks like this
//Class member
std::atomic<uint_fast64_t> counter
//Parallel function
while(counter-- > 0)
{
do something
}
It compiles correctly and executes but it enters an infinite loop because once the counter reaches 0, it is further decremented but it jumps back to the highest integer available thus never stopping.
Changing the type to int64 instead of uint64 solves the issue but I would like to understand why do I need this workaround at all.
My working hypothesis at the moment is that the decrement is done anyway even when the condition is false so when the first thread check the counter at 0 it decrements it anyway and the operation subtraction operation doesn't really care about the encoding of the integers but performs a simple bitwise operation (I forgot which one exactly but I remember additions and subtractions are done by simple bitwise xor and shifts) which in the next iteration is interpreted as the max uint value. Do you think this explanation is reasonable?
Apart from switching from uint to int one option is to switch the operation from a decrement to an increment but can you think of a different algorithm to keep the decrement in this context?
Edit1
Another possible solution I thought of, even though not particularly elegant is, knowing how many threads are actually launched in parallel, to stop the counter at N_Threads with a start value of Tot+NThreads
//In calling function
counter = Tot+NThreads
//Parallel function
while(counter-- > NThreads)
{
do something
}