TCL thread :: send upvar变量未设置

时间:2017-03-24 20:57:51

标签: multithreading tcl send

我的代码如下:

package require Thread

proc p1 {} {

    set tid [thread::create {
        proc executeCommand {command} { 
            return $command
        }
        thread::wait
    }]

    set result ""
    ::thread::send -async $tid [list executeCommand {"Hello thread world"}] result

    #***Do some additional stuff***

    vwait result
    ::thread::release $tid
    puts $result

    return $result

}

p1

在获取包含此代码的.tcl文件之后,我期望子线程返回" Hello thread world"在调用vwait并且'结果'要打印的变量,但这些都不会发生。看起来'结果'变量保持空白。

奇怪的是,当我从一个过程(proc)块中取出代码并获取.tcl文件时,它工作得很好但是我的系统设置方式我需要使用过程。

不确定我做错了什么。

1 个答案:

答案 0 :(得分:1)

“问题”是接收变量(就像vwait)相对于全局命名空间而不是当前范围内的变量; the call to Tcl_SetVar2Ex in the callback上使用了标志TCL_GLOBAL_ONLY(并且Tcl的底层变量实现非常复杂,所以如果可能的话,我们真的想坚持使用API​​):

/*
 * Set the result variable
 */

if (Tcl_SetVar2Ex(interp, var, NULL, valObj,
                  TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG) == NULL) {
    rc = TCL_ERROR;
    goto cleanup;
}

这一般是有意义的,因为你可以从启动后台线程和接收结果之间的过程返回,并且Tcl 真的试图避免做早期绑定

那么结果在哪里?它位于全局 result变量中(::仅表示“我的意思是使用名为this的全局变量”):

% puts $::result
"Hello thread world"

最简单的解决方法是使用变量来执行特定调用所特有的接收。这听起来比实际更复杂,因为我们在线程ID中已经有了一个唯一的标记:

proc p1 {} {
    set tid [thread::create {
        proc executeCommand {command} { 
            return $command
        }
        thread::wait
    }]

    ### Make the name of the global variable (an array element) ###
    set var ::p1results($tid)

    ### This is a simple transformation of what you were already doing ###
    set $var ""
    ::thread::send -async $tid [list executeCommand {"Hello thread world"}] $var

    #***Do some additional stuff***

    vwait $var

    ### Transfer the global variable into a local and remove the global ###
    set result [set $var]
    unset $var

    ### Back to your code now ###
    ::thread::release $tid
    puts $result

    return $result
}

当我试用时,这似乎按预期工作。