我试图与c和tcl共享一个变量,问题是当我试图从tcl读取c线程中的变量时,它会导致分段错误,我不确定这是不是正确的方法,但它似乎适用于in。导致分段错误的部分是,当我尝试打印"Var“时,但我想读取变量,以便在变量发生变化时执行相应的操作。
下面是我正在使用的C代码
void mode_service(ClientData clientData) {
while(1) {
char* Var = (char *) clientData;
printf("%s\n", Var);
usleep(100000); //100ms
}
}
static int mode_thread(ClientData cdata, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]) {
Tcl_ThreadId id;
ClientData limitData;
limitData = cdata;
id = 0;
Tcl_CreateThread(&id, mode_service, limitData, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);
printf("Tcl_CreateThread id = %d\n", (int) id);
// Wait thread process, before returning to TCL prog
int i, aa;
for (i=0 ; i<100000; i++) {aa = i;}
// Return thread ID to tcl prog to allow mutex use
Tcl_SetObjResult(interp, Tcl_NewIntObj((int)id));
printf("returning\n");
return TCL_OK;
}
int DLLEXPORT Modemanager_Init(Tcl_Interp *interp){
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
if (Tcl_PkgProvide(interp, "PCIe", "1.0") == TCL_ERROR) {
return TCL_ERROR;
}
// Create global Var
int *sharedPtr=NULL;
//sharedPtr = sharedPtr = (char *) Tcl_Alloc(sizeof(char));
Tcl_LinkVar(interp, "mode", (char *) &sharedPtr, TCL_LINK_STRING);
Tcl_CreateObjCommand(interp, "mode_thread", mode_thread, sharedPtr, NULL);
return TCL_OK;
}在tcl代码中,每当用户按下按钮时,我都会更改变量模式,例如:
set mode "Idle"
button .startSamp -text "Sample Start" -width 9 -height 3 -background $btnColor -relief flat -state normal -command {set mode "Sampling"}
set threadId [mode_thread]
puts "Created thread $threadId, waiting"发布于 2013-12-11 18:34:40
你的代码一团糟!你需要决定你在做什么,然后就这么做。特别是,您使用的是Tcl_LinkVar,因此您需要决定要链接到哪种类型的变量。如果存储、C访问模式和声明的语义类型不匹配,就会崩溃。
因为您的代码太复杂了,我无法准确地了解您想要做什么,所以我将用不太相关的示例来说明。您需要从它们中找出如何更改代码中的内容,以获得所需的结果。
链接整数变量
让我们做一个简单的例子:一个全局int变量(在任何函数外部声明)。
int sharedVal;您希望您的C代码读取该变量并获取值。简单!只要在范围内阅读它就可以了。您还希望Tcl代码能够写入该变量。简单!在包初始化函数中,放入如下内容:
Tcl_LinkVar(interp /* == the Tcl interpreter context */,
"sharedVal" /* == the Tcl name */,
(char *) &sharedVal /* == pointer to C variable */,
TCL_LINK_INT /* == what is it! An integer */);请注意,在此之后(直到您使用Tcl_UnlinkVar),每当Tcl代码从Tcl变量读取时,都会从C变量中获取当前值并进行转换。
如果您希望该变量位于堆中,那么您可以这样做:
int *sharedValPtr = malloc(sizeof(int));C代码使用*sharedValPtr进行访问,您可以通过以下方式绑定到Tcl:
Tcl_LinkVar(interp /* == the Tcl interpreter context */,
"sharedVal" /* == the Tcl name */,
(char *) sharedValPtr /* == pointer to C variable */,
TCL_LINK_INT /* == what is it! An integer */);链接字符串变量
除了TCL_LINK_STRING之外,还有许多其他语义类型以及TCL_LINK_INT (请参阅文档中的列表),但它们都遵循这种模式。这样,您就可以做到:
char *sharedStr = NULL;Tcl_LinkVar(interp, "sharedStr", (char *) &sharedStr, TCL_LINK_STRING);您还需要知道,字符串将始终与Tcl_Alloc一起分配(对于典型的Tcl内存使用模式,这比大多数系统内存分配器快得多),而不是与任何其他内存分配器一起分配,因此也将始终使用Tcl_Free释放。实际上,这意味着如果从C端设置字符串,则必须使用Tcl_Alloc来分配内存。
正在发布更新通知
最后要注意的是,当您从C端设置变量,但希望Tcl注意到更改已经设置(例如,因为已经设置了trace或因为您已经在Tk中浮现了值),您应该执行Tcl_UpdateLinkedVar,让Tcl知道发生了它应该注意的更改。如果您从不使用traces (或Tk,或vwait命令)来监视变量是否有更新,则可以忽略此API调用。
发布于 2013-12-11 20:08:31
多纳尔的答案是正确的,但我试着向你展示你的ClientData是怎么做的。
为了说明这一点:所有(或几乎所有)接受函数指针的Tcl函数也都接受ClientData类型的参数,当Tcl调用它时,该参数会传递给函数。
让我们看一下这一行:
Tcl_CreateObjCommand(interp, "mode_thread", mode_thread, NULL, NULL);
// ------------------------------------------------------^^^^您总是将NULL作为ClientData传递给mode_thread函数。
在mode_thread函数中,使用传递的ClientData (NULL)将其作为ClientData传递给新的线程:
limitData = cdata;
// ...
Tcl_CreateThread(&id, mode_service, limitData, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);在mode_service函数中,使用ClientData (仍然是NULL)作为指向char数组的指针:
char* Var = (char *) clientData;它是指向地址0x00的指针。
然后告诉printf取消引用这个空指针:
printf("%s\n", Var);这显然会使你的程序崩溃。
https://stackoverflow.com/questions/20504705
复制相似问题