tsv(3tcl)
π tsv β the Tcl threading extension's shared-variable era π
okay bestie, so this is tsv, part of the Tcl threading extension that lets you do script level manipulation of data shared between threads. yes, threads. yes, sharing. we're doing the whole thing. π§
β¨ SYNOPSIS β¨
package require Tcl 8.4
package require Thread ?2.8?
tsv::names ?pattern?
tsv::object varname element
tsv::set varname element ?value?
tsv::get varname element ?namedvar?
tsv::unset varname ?element?
tsv::exists varname element
tsv::pop varname element
tsv::move varname oldname newname
tsv::incr varname element ?count?
tsv::append varname element value ?value ...?
tsv::lock varname arg ?arg ...?
tsv::handlers
tsv::lappend varname element value ?value ...?
tsv::linsert varname element index value ?value ...?
tsv::lreplace varname element first last ?value ...?
tsv::llength varname element
tsv::lindex varname element ?index?
tsv::lrange varname element from to
tsv::lsearch varname element ?options? pattern
tsv::lset varname element index ?index ...? value
tsv::lpop varname element ?index?
tsv::lpush varname element ?index?
tsv::array set varname list
tsv::array get varname ?pattern?
tsv::array names varname ?pattern?
tsv::array size varname
tsv::array reset varname list
tsv::array bind varname handle
tsv::array unbind varname
tsv::array isbound varname
tsv::keyldel varname keylist key
tsv::keylget varname keylist key ?retvar?
tsv::keylkeys varname keylist ?key?
tsv::keylset varname keylist key value ?key value..?
πΈ DESCRIPTION πΈ
This section is all about the commands that make thread shared variables happen. A thread shared variable is literally very similar to a Tcl array, except β and this is the whole plot twist β it gets created in shared memory and can be accessed from many threads at the same time. π
The important feature, the one that makes this whole thing iconic, is that each access to the variable is internally protected by a mutex, so you, the script programmer, do NOT have to take care about locking the variable yourself. she does it for you. no cap. π«Ά
Thread shared variables are not bound to any thread explicitly. That means when a thread which created any of the thread shared variables exits, the variable and its associated memory is not unset/reclaimed. nope. you, the user, have to explicitly unset the variable to reclaim the memory it consumed. it's giving "you made this mess, you clean it up" energy. π
π ELEMENT COMMANDS π
tsv::names ?pattern?β returns the names of shared variables matching the optional ?pattern?, or, if the pattern is ommited, all known variables. every single one. the whole friend group.tsv::object varname elementβ creates an object accessor command for the element in the shared variable varname. with this command you can apply most of the other shared variable commands as method functions of the element object command. and here's the cute part: the object command gets automatically deleted when the element it's pointing at gets unset. self-cleaning icon behavior. β¨
% tsv::set foo bar "A shared string"
% set string [tsv::object foo bar]
% $string append " appended"
=> A shared string appended
tsv::set varname element ?value?β sets the value of the element in the shared variable varname to value, and returns that value to the caller. the value may be ommited, in which case the command just returns the current value of the element. if the element cannot be found, an error is triggered. β οΈtsv::get varname element ?namedvar?β retrieves the value of the element from the shared variable varname. if the optional argument namedvar is given, the value gets stored in that named variable instead. the return value of the command depends on whether you passed that optional argument: if it's ommited and the requested element can't be found in the shared array, the command triggers an error. if you do give the optional argument, the command returns true (1) if the element is found or false (0) if it isn't. two modes, one command, main character energy. πtsv::unset varname ?element?β unsets the element from the shared variable varname. if the optional element isn't given, it deletes the whole variable. gone. bye. π¦tsv::exists varname elementβ checks wether the element exists in the shared variable varname, returning true (1) if it does or false (0) if it doesn't. a vibe check, but for variables. π₯tsv::pop varname elementβ returns the value of the element in the shared variable varname and unsets the element, all in one atomic operation. grab it and yeet it, atomically. πtsv::move varname oldname newnameβ renames the element oldname to newname in the shared variable varname. it effectively performs a get/unset/set sequence of operations, but all in one atomic step. no in-between, no mess. β¨tsv::incr varname element ?count?β similar to the standard Tclincrcommand, but it increments the value of the element in shared variable varname instead of the Tcl variable. numbers going up, we love to see it. πtsv::append varname element value ?value ...?β similar to the standard Tclappendcommand, but appends one or more values to the element in shared variable varname instead of the Tcl variable. string growing era. π±tsv::lock varname arg ?arg ...?β this command concatenates the passed arguments and evaluates the resulting script under the internal mutex protection. during that script evaluation, the entire shared variable is locked. for shared variable commands within the script, internal locking is disabled so no deadlock can occur. it's also allowed to unset the shared variable from within the script. and if the shared variable didn't exist at the time of the first lock operation, it's automatically created. yes, it just spawns. π
% tsv::lock foo {
tsv::lappend foo bar 1
tsv::lappend foo bar 2
puts stderr [tsv::set foo bar]
tsv::unset foo
}
tsv::handlersβ returns the names of all persistent storage handlers enabled at compile time. see ARRAY COMMANDS for the details, bestie. π
π LIST COMMANDS π
These commands are all similar to the equivalently named Tcl command. the difference? they operate on elements of shared arrays. that's the whole twist. π
tsv::lappend varname element value ?value ...?β similar to the standard Tcllappendcommand, but appends one or more values to the element in shared variable varname instead of the Tcl variable.tsv::linsert varname element index value ?value ...?β similar to the standard Tcllinsertcommand, but inserts one or more values at the index list position in the element in the shared variable varname instead of the Tcl variable.tsv::lreplace varname element first last ?value ...?β similar to the standard Tcllreplacecommand, but replaces one or more values between the first and last position in the element of the shared variable varname instead of the Tcl variable.tsv::llength varname elementβ similar to the standard Tclllengthcommand, but returns the length of the element in the shared variable varname instead of the Tcl variable.tsv::lindex varname element ?index?β similar to the standard Tcllindexcommand, but returns the value at the index list position of the element from the shared variable varname instead of the Tcl variable.tsv::lrange varname element from toβ similar to the standard Tcllrangecommand, but returns values between the from and to list positions from the element in the shared variable varname instead of the Tcl variable.tsv::lsearch varname element ?options? patternβ similar to the standard Tcllsearchcommand, but searches the element in the shared variable varname instead of the Tcl variable.tsv::lset varname element index ?index ...? valueβ similar to the standard Tcllsetcommand, but sets the element in the shared variable varname instead of the Tcl variable.tsv::lpop varname element ?index?β similar to the standard Tcllindexcommand, but in addition to returning, it also splices the value out of the element from the shared variable varname in one atomic operation. and in contrast to the Tcllindexcommand, this command returns no value to the caller. plot twist, bestie. πtsv::lpush varname element ?index?β this command performes the opposite of thetsv::lpopcommand. and as its counterpart, it returns no value to the caller. symmetry. we love her. β¨
π ARRAY COMMANDS π
This command supports most of the options of the standard Tcl array command. and in addition to those, it lets you bind a shared variable to some persisten storage databases. currently the persistent options supported are the famous GNU Gdbm and LMDB. these options have to be selected during the package compilation time. the implementation provides hooks for defining other persistency layers, if needed. very extensible of her. π
tsv::array set varname listβ does the same as standard Tclarray set.tsv::array get varname ?pattern?β does the same as standard Tclarray get.tsv::array names varname ?pattern?β does the same as standard Tclarray names.tsv::array size varnameβ does the same as standard Tclarray size.tsv::array reset varname listβ does the same as standard Tclarray set, but it clears the varname and sets the new values from the list atomically. wipe and rewrite in one go. π₯tsv::array bind varname handleβ binds the varname to the persistent storage handle. the format of the handle is<handler>:<address>, where<handler>is"gdbm"for GNU Gdbm and"lmdb"for LMDB, and<address>is the path to the database file. πtsv::array unbind varnameβ unbinds the shared array from its bound persistent storage. we're letting go. π¦tsv::array isbound varnameβ returns true (1) if the shared varname is bound to some persistent storage, or zero (0) if not.
okay so that's part 1 and there is literally more coming, don't go anywhere bestie π
π KEYED LIST COMMANDS π
okay bestie so these ones are borrowed from the TclX package β keyed lists give you a whole structured data type built on top of regular Tcl lists. it's giving... structs in C. literally the same energy. π«Ά
a keyed list is a list where every element holds a key and value pair. each pair is stored as a list of its own, where the key is the first element and the value is the second. those pairs get called fields. here's a whole example, no cap:
{{NAME {Frank Zappa}} {JOB {musician and composer}}}
and yes, fields can contain subfields β '.' is the separator character. subfields are literally fields where the value is another keyed list. so this next one has top level fields ID and NAME, plus subfields NAME.FIRST and NAME.LAST:
{ID 106} {NAME {{FIRST Frank} {LAST Zappa}}}
there is no limit to how deep the subfields recurse, so you can build entire complex data structures, go off. keyed lists are built and accessed through a bunch of commands, and here's the thing β all keyed list management commands take the name of the variable holding the keyed list as an argument (i.e. passed by reference), instead of passing the list directly. periodt.
tsv::keyldel π
tsv::keyldel varname keylist key
delete the field specified by key from the keyed list keylist in the shared variable varname. this nukes both the key and the value out of the keyed list. bye bye field β¨
tsv::keylget π
tsv::keylget varname keylist key ?retvar?
return the value associated with key from the keyed list keylist in the shared variable varname.
- if the optional retvar is not specified, the value comes back as the result of the command. in that case, if key is not found in the list, you get an error. π
- if retvar is specified and key is in the list, the value goes into the variable retvar and the command returns
1because the key was present within the list. π - if key isn't in the list, the command returns
0, and retvar is left unchanged. no touchy. - if
{}is specified for retvar, the value is not returned at all β which lets the Tcl programmer check whether a key is present in a keyed list without setting a variable as a side-effect. lowkey genius.
tsv::keylkeys πΈ
tsv::keylkeys varname keylist ?key?
return the a list of the keys in the keyed list keylist in the shared variable varname. (yes, "the a list", we're keeping the lore fr fr π«Ά)
if key is specified, then it is the name of a key field who's subfield keys are to be retrieved. digging into the layers bestie π
tsv::keylset π
tsv::keylset varname keylist key value ?key value..?
set the value associated with key, in the keyed list keylist, to value.
- if the keylist does not exists, it is created. β¨
- if key is not currently in the list, it will be added.
- if it already exists, value replaces the existing value. out with the old.
- multiple keywords and values may be specified, if desired. go wild. π₯
π DISCUSSION π
the current implementation of thread shared variables allows for easy and convenient access to data shared between different threads. internally, the data is stored in Tcl objects and all package commands operate on the internal data representation β which minimizes shimmering and improves performance. obsessed. special care has been taken to assure that all object data is properly locked and deep-copied when moving objects between threads. π
but here's the tea: due to the internal design of the Tcl core, there is no provision of full integration of shared variables within the Tcl syntax, unfortunately. π all access to shared data must be performed with the supplied package commands. also, variable traces are not supported. but even so, the benefits of easy, simple and safe shared data manipulation outweights imposed limitations. (their spelling, we respect it π)
π CREDITS π
thread shared variables are inspired by the nsv interface found in AOLserver, a highly scalable Web server from America Online. iconic lineage honestly.
π SEE ALSO π
threadtpoolttrace
π KEYWORDS π
lockingsynchronizationthread shared datathreads
that's a wrap bestie!! this one came from the Tcl Threading docs, version 2.8, page tsv(3tcl) β go forth and share your data safely, you main character π¦β¨π
π¦ where this page comes from
- debian trixie: tcl-thread 1:2.8.11-2
- ubuntu questing: tcl-thread 1:2.8.11-2
- ubuntu resolute: tcl-thread 1:2.8.12-1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms