tcl 多线程就像在 c 中一样,很难用过程执行线程

tcl multithreading like in c, having hard time to execute thread with procedure

我曾经在 C 中工作,在那里可以很容易地使用我选择的特定函数创建线程。

现在在 tcl 中我不能使用线程启动我想要的特定功能,我试过这个:

package require Thread

proc printme {aa} {
    puts "$aa"
}

set abc "dasdasdas"

set pool [tpool::create -maxworkers 4 ]
# The list of *scripts* to evaluate
set tasks {
    {puts "ThisisOK"}
    {puts $abc}
    {printme "1234"}
}

# Post the work items (scripts to run)
foreach task $tasks {
    lappend jobs [tpool::post $pool $task]
}

# Wait for all the jobs to finish
for {set running $jobs} {[llength $running]} {} {
    tpool::wait $pool $running running 
}

# Get the results; you might want a different way to print the results...
foreach task $tasks job $jobs {
    set jobResult [tpool::get $pool $job]
    puts "TASK: $task"
    puts "RESULT: $jobResult"
}

我总是得到: 执行错误206: invalid command name "printme"invalid command name "printme" 在执行时 "printme "1234"" 从内部调用 "tpool::get $pool $job"

为什么?

你的问题是,Tcl 线程模型与 C 语言中使用的模型非常不同。Tcl 的模型基本上是 'shared nothing by default' 主要基于消息传递的模型。

所以池中的每个线程都是一个独立的解释器,并且对 proc printme 一无所知。你需要用你需要的过程来初始化这些解释器。

查看 ::tpool::create 命令的文档,它有一个选项可以提供一个 -initcmd 您可以在其中定义或 package require 您需要的东西。

所以试试这个来初始化你的线程:

set pool [tpool::create -maxworkers -initcmd {
    proc printme {aa} {
        puts "$aa"
    }}]

https://www.tcl.tk/man/tcl/ThreadCmd/tpool.htm#M10

更详细地回答您的评论:

不,没有办法让 Tcl 线程像 C 线程一样工作并自由共享对象和过程。这是一个基本的设计决策,允许 Tcl 拥有一个没有大量全局锁的解释器(与例如 CPython 相比),因为大多数事情都是线程本地的并且使用线程本地存储。

但是有一些方法可以使多线程解释器的初始化和使用更容易。一个是 ::tpool::create 中的 -initcmd 参数,它允许您为池中的每个解释器 运行 初始化代码,而无需手动执行。如果您所有的代码都在一个包中,您只需添加一个 package require 并正确初始化您的解释器。

如果你真的想在多个线程之间共享状态,你可以使用::tsv子命令。它允许您以明确的方式在线程之间共享数组和其他内容。但在幕后,它涉及您可能从 C 中了解到的典型锁和互斥锁来调解访问。

thread 包中还有另一组命令,可让您更轻松地进行初始化。这是 ttrace 命令,它允许您简单地 trace 在一个解释器中执行的内容并在另一个解释器中自动重复它。它非常聪明,只有 shares/copies 你真正用于目标的过程,而不是预先加载所有东西。