Title:

threadLock() - create an object of class threadLock which acts as a database into which variables that are shared between two threads can be stored.

Usage:

threadLock(name = "",..., attach = F)

Arguments:

name:
the name under which this object is stored internally and can be retrieved for future use, in the absence of the object returned from the call to threadLock
...:
named values which are assigned to the object created by this call. These are initial values or this database that are available immediately the object is created to all threads which have this object in their search paths or a handle to it.
attach:
either a logical value indicating whether we should automatically attach() this object as a database to the search path at position 2, or a numeric index specifying the position in the search path at which this object is to attached.

Side Effect:

A name table/database is created internally and a handle to it is returned. If attach is T, the search path is altered by inserting this object at position ??? (What is appropriate - 1 or 2)

NOTE:

It is intended that this object be shared between threads. Therefore it should be visible in the search path for the "sharing" threads. If it is created by the parent thread it will be assigned to the corresponding thread database 0. When new threads are created, these will have this database in their second slot of the search path and so will be able to access this object (provided they don't alias it locally!).

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.

See Also:

getLock()
tryGetLock()
threadLock class
threadLock.assign()

Examples:

     
          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))
The idea is this:
a 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.

Key Words:

User Level Threads

Last modified: Thu Feb 6 11:48:59 1997