|Welcome to the Monastery|
...so both foo()'s point to the same cloistered object.
Nope. That's not really true. When you do use threads::shared(), what in fact happens is that in the background a thread is started. The dataspace of that hidden thread, contains the final version of each shared variable.
All the other "shared" variables are basically simply tied variables to the "threads::shared::xxx" module. When want to get the value of a shared scalar, internally the FETCH subroutine gets excuted which fetches the value from the hidden thread, stores it in your local thread dataspace (mainly for consistency with XS modules) and returns that value. So the same value exists both in your thread as well as in the hidden thread.
Same thing happens if you want to store a value in a shared scalar: the STORE subroutine stores the new value both in your local thread dataspace and in the hidden thread's dataspace. Some mutexing is involved of course. But e.g. incrementing a shared variable without locking is not guaranteed to increment. This is because incrementing with tied variables is implemented as a FETCH and a STORE, and between the FETCH and the STORE in one thread, another thread can already have done a FETCH. The following will rarely show the expected total:
You'd expect $scalar to have the value of 10 * 100000 = 1000000, however unless you have a very fast machine, you will find it to be significantly less. To do this properly, you would have to lock the variable before doing the increment. For example:
This should show the expected result: 1000000.