What got me started was following multiple threads calling the same MIME decomp code, and preempting each other. I flashed back to the the techniques to do recursion, and the use of the activation record to store all working variables going through the common code on each cycle through. In OO, a new object encapsulates all of the object specific working space (or pointers to heap space).
Would my package allocate a hash during thread 1(T1), then be preempted by T2, which, finding the hash already there just start stuffing more into it.
My training goes back to linear shared physical memory space for all processes; not this managed buckets of private pointers to allocated heap space.
I feel better now... thanks ... I guess I am a hand-on sort of person. | [reply] |
At the simplest level, all you need to know is that unless you explicitly share a variable, only the thread that declared it can access it. They are invisible to other threads.
However, there is a caveat. That all variables instantiated before you spawn a thread, are cloned into that thread. Both the spawned thread and the spawning thread will have entirely independent copies of those variables that existed at the point of thread creation. The effect is very similar to the fork mechanism whereby the state of the process is cloned and each process (parent and child) have their own copies of everything that existed at the fork point.
However, there is a caveat with that description also, in as much as process global resources, like the standard file handles, pre-existing sockets etc. are not entirely independent of each other. This has consequences that you need to be aware of. For example:
use threads;;
open O, '>', 'junk.dat';; ## Open a file
print O $_ for 1 .. 100; ## print some stuff to it
print tell O;; ## print the file pointer position
392
async{ ## spawn a thread
print tell O; ## inherits a (cloned) copy of the file
+ handle
392 ## complete with pre-existing state
print O $_ for 1 .. 100; ## print some more stuff from within th
+e thread
print tell O; ## And it's copy of the file handle ref
+lects the change
784
};;
print tell O;; ## but back in the main thread the orig
+inal doesn't see it
392
print O $_ for 1 .. 100;; ## even after local modifications
print tell O;; ##
784
close O; exit;;
c:\test>wc -l junk.dat ## All the output ended up in the file,
+
300 junk.dat ## But neither threads file handle
## reflects the true pointer position.
That's probably the worst anomalous behaviour. It's 'safe' to use file handles from more than one thread, provided you use locking to prevent interspersion of output, but do not rely upon the output from tell.
Another consequence of the cloning is that if you allocate large data structure before spawning threads, each thread spawned afterward will get a copy of that data structure regardless of whether it needs it or not.
The trick here is to spawn early and require packages within the threads that need them rather than useing them. With care, you can control (to some degree) what packages are loaded into what threads.
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] |