我正在尝试将一个 Tcl 变量链接到一个 C 变量,以便在 C 线程创建期间将指针传递给最新的指针并拥有一个 TCL-C 线程共享变量(我不认为我可以使用 native TCL 线程共享变函数)。 我很难链接这两个变量。 这是我的做法:
#Tcl code, calling the C function:
set linkedVar 98
puts "linkedVar: $linkedVar"
load [file join [pwd] libCextension[info sharedlibextension]]
set threadId [createThreadC]
puts "Created thread n° $threadId"
puts "linkedVar: $linkedVar"
createThreadC
函数创建一个 C 线程,返回其 ID 并尝试使用 linkedVar
创建一个链接。
// C function called by Tcl
static int
createThreadC_Cmd(
ClientData cdata,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{
int linkedVar=2;
Tcl_LinkVar(interp, "linkedVar", (char *) &linkedVar, TCL_LINK_INT);
linkedVar=1;
...
# Thread creation, return Tcl object with thread ID
...
return TCL_OK;
}
这是输出:
linkedVar: 98
Created thread n° -1227199680
linkedVar: 35
linkedVar
值已更改,因为 C 程序必须这样做,但它存储了错误的变量,应该是 1 而不是 35。
是 (char *) &linkedVar
转换错了吗?
最佳答案
您正在正确使用 Tcl_LinkVar
几乎;您的原始代码类型正确。但这不是问题所在!
问题是您在 Tcl 解释器(具有相当长的生命周期)和 C 堆栈上具有短生命周期的变量之间进行链接。在 createThreadC_Cmd
之后,链接指向未使用的堆栈,并且通常会在之后立即用于其他事情。这是正式的未定义行为,而且非常糟糕。您需要做的是确保 C 变量的生命周期至少与解释器的生命周期一样长。
最简单的修复方法是使用全局(或static
局部)变量。唯一的缺点是同一变量将在对 createThreadC_Cmd
的所有调用之间共享;有时这根本不是问题,但我怀疑你的情况并非如此。因此,您需要在别处分配一些空间。如果您不希望您创建的解释器消失,那么最便宜的方法就是使用 malloc
获得一点空间,然后将链接指向该空间;然后你可以泄漏内存并停止担心它(这是不干净的,但很容易做到)。如果你想清理,你做几乎相同的事情,但注册一个适当的关闭 Hook ,释放
内存;根据实际消失的情况,Tcl 具有三种关闭 Hook :
- Interpreter 关闭 Hook 是使用
Tcl_CallWhenDeleted
创建的
- Thread 关闭 Hook 是使用
Tcl_CreateThreadExitHandler
创建的
- Process/library shutdown hooks 是用
Tcl_CreateExitHandler
创建的(你不需要它来删除内存,除非你需要非常干净;警告,很难在调用它们时立即删除内存)。
我不太确定哪个适合你;这取决于您共享变量的范围。 (我希望您不打算跨线程共享它;设计上不会很好地工作。)
关于c - TCL-C API : Tcl_LinkVar function use,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12315049/