[ Team LiB ] Previous Section Next Section

Shared Variables

Standard Tcl variables are a per-interpreter resource; an interpreter has no access to variables in another interpreter. For the simple exchange of information between threads, you can substitute the values of variables into a script that you send to another thread, and obtain the return value of a script evaluated by another thread. But this technique is inadequate for sharing information among multiple threads, and inefficient when transferring large amounts of information.

The Thread extension supports the creation of thread-shared variables, which are accessible by all threads in an application. Thread-shared variables are stored independent of any interpreter, so if the thread that originally created a shared variable terminates, the shared variable continues to exist. Shared variables are stored in collections called arrays. The term is somewhat unfortunate, because while shared variable arrays are similar to standard Tcl arrays, they do not use the same syntax. Your application can contain as many shared variable arrays as you like.

Because of the special nature of shared variables, you cannot use the standard Tcl commands to create or manipulate shared variables, or use standard variable substitution syntax to retrieve their values. (This also means that you cannot use shared variables as a widget's -textvariable or -listvariable, with vwait or tkwait, or with variable traces.) All commands for interacting with shared variables are provided by the Thread extension in the tsv namespace. Most of the tsv commands are analogous to Tcl commands for creating and manipulating standard Tcl variables. Table 21-3 on page 346 describes all of the tsv commands.

You create a shared variable with tsv::set, specifying the array name, the variable name (sometimes also referred to as the shared array element), and the value to assign to it. For example:

tsv::set application timeout 10

To retrieve the value of a shared variable, either use tsv::set without a value or call tsv::get. The two commands shown below are equivalent:

tsv::set application timeout
tsv::get application timeout

All shared variable commands are guaranteed to be atomic. A thread locks the variable during the entire command. No other thread can access the variable until the command is complete; if a thread attempts to do so, it blocks until the variable is unlocked. This simplifies the use of shared variables in comparison to most other languages, which require explicit locking and unlocking of variables to prevent possible corruption from concurrent access by multiple threads.

This locking feature is particularly useful in the class of tsv commands that manipulate lists. Standard Tcl commands like linsert and lreplace take a list value as input, and then return a new list as output. Modifying the value of a list stored in a standard Tcl variable requires a sequence like this:

set states [linsert $states 1 California Nevada]

Doing the same with shared variables is problematic:

tsv::set common cities \
    [linsert [tsv::get common cities] 1 Yreka Winnemucca]

After reading the shared variable with tsv::get, another thread could modify the value of the variable before the tsv::set command executes, resulting in data corruption. For this reason, the tsv commands that manipulate list values actually modify the value of the shared variable. Data corruption by another thread won't occur because the shared variable is locked during the entire execution of the command:

tsv::linsert common cities 1 Yreka Winnemucca
    [ Team LiB ] Previous Section Next Section