set t6 [thread::create] ; thread::send -async $t6 "set i1 0"
This is working fine without any errors.
set t5 [thread::create] ; thread::send -async $t5 "date"
But this is erroring out : invalid command name "date" while executing "date"
What could be the reason ?
CodePudding user response:
The date
“command” is not actually a command. It's another program, /bin/date
(or /usr/bin/date
, depending on exactly how your system is set up). Or, on Windows it is a builtin of CMD.EXE
.
What's going on is that you're using tclsh
interactively; it detects this and marks the current main interpreter as interactive (sets the global tcl_interactive
variable to 1
) and the unknown command handler sees that and enables extra behaviours, such as expansion of command names and automatic calling out to external programs; it's effectively rewriting date
into:
exec {*}[auto_execok date]
The auto_execok
command in Tcl does path searching and all the extra stuff required for running inside bash
or cmd
(it's got a range of options it can do). On my system, auto_execok date
returns /bin/date
, but there's no particular reason why it might do so on yours; all we know is that it found something.
The other thread is not interactive; it's not talking directly to you. That means you need to send it full commands, not abbreviations, not things that are shorthands. It also doesn't write results to the console by default; you need to add that too. Try this:
set t5 [thread::create]
thread::send -async $t5 "puts \[[list exec {*}[auto_execok "date"]]\]"
This gets messy fast. It's a lot easier to create procedures in the other thread to do most of the work and then call them:
set t5 [thread::create]
thread::send $t5 {
proc runAndPrint {command args} {
puts [exec {*}[auto_execok $command] {*}$args]
}
}
thread::send -async $t5 [list runAndPrint "date"]
Note that I'm using list
to build the command to send over when it isn't a literal. I don't need to do that, but it is an extremely good habit to have as it means that your code Just Works As Expected™ when you start passing arguments with spaces and other meta-characters in; you don't have to think about getting quoting right, as list
does that for you (by design). It's great for creating a command to execute and it guarantees that there are no surprise substitutions. If you need substitutions, calling a procedure (or lambda term, or method) is so much easier to make reliable; that can uplevel
and upvar
if it needs to.