This is the third and last article in the “Concurrency in Tcl” series. The previous postings introduced event handling and threading as possible solutions to the problem of executing several things at the same time, using examples which required basically no communication between the various parts at all.
For most actual applications this is not realistic. Their parts will have to communicate with each other in some way to solve the user’s goals. Tcl’s abilities in this area are the topic of this post.
At the core of most solutions for communication we have channels. We saw instances of them already in the previous articles, in the special form of sockets, allowing the transfer of data over a network.
As such they are mostly used for applications whose parts are distributed over multiple system. However, as this is a very abstract interface to the network they are also usable when all the applications’ components are on the same host (local multi-processing), or even in the same process (multi-threading).
In the case of local multi-processing another option is the use of anonymous “pipes”, which can be opened through a special syntax of the file argument to Tcl’s ‘open‘ command. In the simplest case this allows the monitoring of a child process using event handling, up to full-fledged duplex communication with the child’s standard channels.
Going back to multi-threaded applications the use of sockets for communication between the threads has one possible disadvantage, all communication goes through the OS, despite the application residing in a single process. On the other hand, together with the previously discussed apartment model, this means that an application can be seamlessly moved between multi-threaded and multi-processed states without having to change its core functionality. It always sees a set of logical processes, regardless of their representation or location on the host.
Still, if the indirect routing through the OS is considered unacceptable for some reason, then packages like Memchan or Tcl 8.5’s reflected/virtual channels allow the setup of channels between threads without making the data available outside of the application’s process.
If the parts of an application do more than just send data between them (i.e. they are able to trigger actions in each other) then it is useful to work at a higher level of abstraction.
In Tcl that is the ability to “send” scripts around, for execution by the receiver, with results returned to the sender if required. This ability has been in Tcl for a long time, with Tk’s ‘send‘ command allowing GUI applications on the same display to talk to each other in this manner.
With the advent of sockets in the Tcl core, actually at the same time as core event handling support moved from Tk into Tcl, we quickly got a package implementing the same paradigm running over this mechanism of communication, namely “comm“.
And for threads we again have the same paradigm, implemented via ‘thread::send‘.
An interesting point is that with reflected (virtual) channels it is possible to implement a channel (i.e. a byte stream) on top of a message-passing interface (essentially a thread::send), whereas with sockets, channels were used to implement the message passing interface. Showing that both types of communication are equivalent in power even while each is geared towards different modes of communication (data streams vs. executable messages).
Title photo courtesy of Gerd Altmann on Pixabay.