T, the search path is altered
by inserting this object at position ??? (What is appropriate - 1 or 2)
A child thread can either assign into this object on the search path or explicitly call threadLock.assign() to create or modify a variable. Such a change gets broadcasted to sibling threads that have this object in their search path and are interested in the relevant variable.
l = threadLock("num.threads", value = NULL, num.threads = 0, attach = 2)
# create a local version of a function that will be handed to
# newly created children threads as their task.
thread.routine <- function(name) {
# should have to lock get num.threads unless the get action
# automatically locks the threadLock object. Since we are getting
# a copy of this, that makes sense. If we want to prohibit other
# threads from modifying the database, we can lock the whole thing
# explicitly at the S level with getLock()
threadLock.assign(l,"num.threads",num.threads+1)
# or more simply
# assign(l, "num.threads",num.threads+1)
i = 0 # create a local version of i
while(i < 100) { # do 100 repetitions of the loop
cat("Thread", name, i,"\n")
i = i + 1
}
}
tA = thread(Quote(thread.routine("A")))
tB = thread(Quote(thread.routine("A")))
getLock(l, condition = Quote(num.threads == 0))
|
|---|
threadLock object is created and the value of num.threads
is assigned the value 0 in this object. Additionally, this object is
attached to the search path at position 2, and the threads own database is in
position 1. (What happens to position 0).
Now we create a local function to be called in a new thread. This is stored
in the current thread's, P, database. Now, two new threads are created
and these each create their own database located in their search path at position 1.
The parent's database is at position 2 and so the threadLock
object is at position 3, by default, since the parents search path is appended/inherited
by child threads and the new threads own database is attached at the top position.
It is critical that the parent thread, P, and the other threads, A and B, don't create local versions of any variables that are correctly located in databases lower in the search path. For example, if thread A creates a variable num.threads locally using something like the following expression
num.threads = num.threads + 1
When evaluated, the RHS of this expression retrieves the value of num.threads
from the databases on the search path, and in our example will find this in
the threadLock object in position 3 of the search path.
However, the expression assigns the resulting value to the database in position 1
which is the threads own database, not shared by any other thread in our example.
So such expression must be avoided or accompanied by removing the object. Instead,
the computations should done inline or assigned to temporary variables with names
that don't alias important variables used in synchronization.