0

Is it possible to pass between TCL threads (created with TCL command - thread::create) commands created in C (i.e. with Tcl_CreateObjCommand) and how?

Thanks.

1 Answer 1

4

All Tcl commands are always coupled to a specific interpreter, the interpreter passed to Tcl_CreateObjCommand as its first parameter, and Tcl interpreters are strictly bound to threads (because the Tcl implementation uses quite a few thread-specific variables internally in order to reduce the number of global locks). Instead, the implementation coordinates between threads by means of messages; the most common sort of message is “here is a Tcl script to run for me” and “here are the results of running that script” though there are others.

So no, Tcl commands can't be shared between threads. If you've written the code for them right (often by avoiding globals or adding in appropriate locks) you can use the same command implementation in multiple interpreters in multiple threads, but they're not technically the same command, but rather just look the same at first glance. For example, if you put a trace on the command in one thread, that'll only get its callbacks invoked in that one interpreter, not from any other interpreter that has a command with the same implementation and with the same name.


You can make a delegate command in the other threads that asks the main thread to run the command and send you the results back.

package require Thread

# This procedure makes delegates; this is a little messy...
proc threadDelegateCommand {thread_id command_name} {
    # Relies on thread IDs always being “nice” words, which they are
    thread::send $thread_id [list proc $command_name args "
        thread::send [thread::id] \[list [list $command_name] {*}\$args\]
    "]
}

# A very silly example; use your code here instead
proc theExampleCommand {args} {
    puts "This is in [thread::id] and has [llength $args] arguments: [join $args ,]"
    return [tcl::mathop::+ {*}$args]
}

# Make the thread
set tid [thread::create]
puts "This is [thread::id] and $tid has just been created"

# Make the delegate for our example
threadDelegateCommand $tid theExampleCommand

# Show normal execution in the other thread
puts [thread::send $tid {format "This is %s" [thread::id]}]

# Show that our delegate can call back. IMPORTANT! Note that we're using an asynchronous
# send here to avoid a deadlock due to the callbacks involved.
thread::send -async $tid {
    after 5000
    theExampleCommand 5 4 3 2 1
} foo
vwait foo
Sign up to request clarification or add additional context in comments.

1 Comment

many thanks for your detailed answer. I appreciate your ever insightful and well presented replies. Issue clarified.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.