SetSharedVariable
effectively causes count
to be always evaluated on the main kernel. Some of the following description consists of guesses and might not be accurate enough, but I think it illustrates well enough in what way things are going wrong. (As Oleksandr said, it's a race condition.)
There are two ways count
may be accessed that will cause a callback to the main kernel: reading or setting its value. count++
causes a single callback: it sets the value. count = count+1
triggers two callbacks: a read and a set. The key point to understand that the order of accesses coming from different subkernels is unpredictable, and their order affects the result.
What seems to happen is that first all three subkernels read the value of count
. Accidentally all three reads happen before any of the writes take place, so all three reads result in 1
. Now all subkernels compute 1+1
to obtain 2
. Finally all of them will set this value to count
.
You can see that when there are two kinds of accesses, both reads and writes, then the order of the operations becomes critical. Theoretically count
could end up with any value between 2
and 4
in your program, depending on the order of operations, and the result of 2
is just accidental.
You could fix this problem in two ways:
Make sure that all of count = count+1
is evaluated in a single go before allowing another subkernel to access count
in any way:
count = 1;
SetSharedVariable[count];
ParallelEvaluate[CriticalSection[{lock}, count = count + 1]]
Restrict your accesses to reads only, with no writes. In other words, use functional programming and avoid side effects. This will also eliminate all the extra callbacks to the main kernel for write access and synchronization, which would slow down your program significantly. More info here and here.