【问题标题】:TCL thread::send upvar variable not being setTCL thread::send upvar 变量未设置
【发布时间】:2017-03-24 20:57:51
【问题描述】:

我的代码如下所示:

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 文件后,我的期望是子线程在调用 vwait 并打印出“结果”变量后返回“Hello thread world”,但这些都没有发生。 'result' 变量似乎保持空白。

奇怪的是,当我将代码从过程 (proc) 块中取出并获取 .tcl 文件时,它可以完美运行,但是根据我的系统设置方式,我需要使用过程。

不知道我做错了什么。

【问题讨论】:

    标签: multithreading tcl send


    【解决方案1】:

    “问题”是接收变量(就像vwait)是相对于全局命名空间定位的,而不是当前范围内的变量;标志TCL_GLOBAL_ONLY 用在the call to Tcl_SetVar2Ex in the callback 上(而且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 真的试图避免进行早期绑定.

    那么结果去哪儿了?它在 global 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
    }
    

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

    【讨论】:

    • 是的!这非常有效 - 感谢 Donal 快速且极其准确的回复。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多