Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Understanding threading in Tcl

2 views
Skip to first unread message

Chris Vitalos

unread,
Jun 24, 2002, 8:36:16 PM6/24/02
to
Hi, there..

I'm trying to understand how to pass messages and data between threads using
simple scripts in Tcl.

Consider these two test scripts:

============================================================================
# A.TCL

set my_thread_id [testthread id]
set in_buffer {}

proc kill {} {
global my_thread_id
puts stderr "$my_thread_id: I'm dead"
testthread exit
}

proc recv_msg { orig_thread_id data } {

upvar $orig_thread_id oti
upvar $data d
global in_buffer

set list [split $in_buffer ":"]
set oti [lindex $list 0]
set d [lindex $list 1]

}

proc send_msg { dest_thread_id data } {

global my_thread_id
testthread send -async $dest_thread_id \
"set in_buffer \"$my_thread_id:$data\""

}

while {1} {
puts stdout "$my_thread_id: Waiting for inbound msg"
set after_id [after 10000 kill]
vwait in_buffer
after cancel $after_id
puts stdout "$my_thread_id: message arrived -> $in_buffer"
recv_msg orig_thread_id datastring
send_msg $orig_thread_id "ACK $datastring"
}
# END A.TCL
============================================================================
============================================================================
# C.TCL

set my_thread_id [testthread id]
set in_buffer {}


proc recv_msg { orig_thread_id data } {

upvar $orig_thread_id oti
upvar $data d
global in_buffer

set list [split $in_buffer ":"]
set oti [lindex $list 0]
set d [lindex $list 1]

}


proc send_msg { dest_thread_id data } {

global my_thread_id
testthread send -async $dest_thread_id \
"set in_buffer \"$my_thread_id:$data\""

}

set dest_thread_id [testthread create]
testthread send -async $dest_thread_id {source a.tcl}
send_msg $dest_thread_id "Hi!"

# End C.TCL

============================================================================

If I source "C.TCL" in a threads enabled tclsh, I get this output ->

============================================================================

% source c.tcl
% 608: Waiting for inbound msg
608: message arrived -> 868:Hi!
608: Waiting for inbound msg
608: I'm dead

% puts $in_buffer

%
============================================================================

I expected the contents of in_buffer at the end of the run to be "ACK Hi!"
...

I'm wondering why can't bi-directional, interthread communications be
achieved here ???

Thanks for your insight !!!!


David Gravereaux

unread,
Jun 24, 2002, 9:21:58 PM6/24/02
to
"Chris Vitalos" <vit...@attbi.com> wrote:

>set my_thread_id [testthread id]

testthread? First, get the real one. That one dates back to 8.1 and is not a
separate package and ends life with tcltest.

http://sourceforge.net/project/showfiles.php?group_id=10894&release_id=51364
--
David Gravereaux <davy...@pobox.com>
Tomasoft Engineering, Hayward, CA
[species: human; planet: earth,milkyway,alpha sector]

Zoran Vasiljevic

unread,
Jun 29, 2002, 5:27:31 AM6/29/02
to
"Chris Vitalos" <vit...@attbi.com> wrote in message news:<4WOR8.310690$cQ3.17101@sccrnsc01>...

> Hi, there..
>
> I'm trying to understand how to pass messages and data between threads using
> simple scripts in Tcl.
>

Eh, me too!

(ok, that was a joke... :)

Seriously...

First of all, you should be using the 2.2 version of the Tcl
extension, at least. You can download it from SourceForge
(it is in the Tcl project area).
You can also checkout the latest status from the CVS of the
Tcl project. There you'll find (soon to be released, eh...)
2.4 version of the extension, with some improved capabilities.

A. Passing data.

There are two ways to pass data between threads.
First is to use thread::send mechanism and pass
data encapsulated within Tcl scriptlets:

% set tid [thread::create]
% set mylist [list 1 2 3 4 5 6 7 8 9 0]
% thread::send "set mylist $mylist"
=> 1 2 3 4 5 6 7 8 9 0

This will re-create the variable "mylist" in the thread $tid.
Not very efficient and elegant, but ok for some quick/dirty
transfers of small amount of data.

Another way is to use thread shared variables facility
(explained in the package doc):

% tsv::set myvar mylist [list 1 2 3 4 5 6 7 8 9 0]
% set tid [thread::create]
% thread::send $tid [tsv::set myvar mylist]
=> 1 2 3 4 5 6 7 8 9 0

This is *way* faster, properly interlocked, thus safe,
and you can share large amounts of (structured) data
between large number of threads easily.
This way you also avoid object shimmering.
Have a look on list of tsv::* commands in the 2.4 version.

B. Passing messages

Message passing is achieved with thread::send, as already
illustrated above. There are however some extensions in
the 2.4 version allowing you to do asynchronous callbacks
in a very simple fashion:

set tid [thread::create]
thread::send -async $tid "info vars" result
vwait result
set result
=> tcl_version tcl_pkgPath tclDefaultLibrary env tcl_patchLevel tcl_platform

This way you can post a message to thread and attend to
the result by entering the event loop when you can (will).
This is very handy for doing non-blocking calls to
libraries w/o non-blocking interface; for example to some
external databases or such.
You can find out more about that in the extension docs.

So, I encourage you to either download the 2.2 version
of the Tcl threading extension or, better yet, checkout
the latest status from the CVS, or even better, look for
the 2.4 version in couple of days.

----

I have (finally!) solved documentation maintenance problems
(many thanks to Joe English for his marvelous TMML and
Rolf Ade for his help in getting the tDOM/TMML work seamlessly)
so I'll be releasing the 2.4 version of the threading extension
within couple of days (mid next week). This will perfectly match
the time frame for the Tcl 8.4 core. This core version is
supporting threads much better than previous versions so you might
want to use the Tcl 8.4 while experimenting with Tcl-level threading.

Cheers,
Zoran

0 new messages