tsv(3tcl)

πŸ“¦ version 2.8.12, in debian trixie, ubuntu questing, ubuntu resolute

πŸ’– 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 Tcl incr command, 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 Tcl append command, 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 Tcl lappend command, 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 Tcl linsert command, 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 Tcl lreplace command, 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 Tcl llength command, 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 Tcl lindex command, 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 Tcl lrange command, 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 Tcl lsearch command, 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 Tcl lset command, but sets the element in the shared variable varname instead of the Tcl variable.
  • tsv::lpop varname element ?index? β€” similar to the standard Tcl lindex command, 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 Tcl lindex command, this command returns no value to the caller. plot twist, bestie. 😭
  • tsv::lpush varname element ?index? β€” this command performes the opposite of the tsv::lpop command. 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 Tcl array set.
  • tsv::array get varname ?pattern? β€” does the same as standard Tcl array get.
  • tsv::array names varname ?pattern? β€” does the same as standard Tcl array names.
  • tsv::array size varname β€” does the same as standard Tcl array size.
  • tsv::array reset varname list β€” does the same as standard Tcl array 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 1 because 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 πŸ‘€

  • thread
  • tpool
  • ttrace

πŸ”‘ KEYWORDS πŸ”‘

  • locking
  • synchronization
  • thread shared data
  • threads

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