首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >TCL_LINK_STRING导致分段故障(核心转储)

TCL_LINK_STRING导致分段故障(核心转储)
EN

Stack Overflow用户
提问于 2013-12-11 04:37:43
回答 2查看 515关注 0票数 1

我试图与c和tcl共享一个变量,问题是当我试图从tcl读取c线程中的变量时,它会导致分段错误,我不确定这是不是正确的方法,但它似乎适用于in。导致分段错误的部分是,当我尝试打印"Var“时,但我想读取变量,以便在变量发生变化时执行相应的操作。

下面是我正在使用的C代码

代码语言:javascript
复制
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代码中,每当用户按下按钮时,我都会更改变量模式,例如:

代码语言:javascript
复制
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"
EN

回答 2

Stack Overflow用户

发布于 2013-12-11 18:34:40

你的代码一团糟!你需要决定你在做什么,然后就这么做。特别是,您使用的是Tcl_LinkVar,因此您需要决定要链接到哪种类型的变量。如果存储、C访问模式和声明的语义类型不匹配,就会崩溃。

因为您的代码太复杂了,我无法准确地了解您想要做什么,所以我将用不太相关的示例来说明。您需要从它们中找出如何更改代码中的内容,以获得所需的结果。

链接整数变量

让我们做一个简单的例子:一个全局int变量(在任何函数外部声明)。

代码语言:javascript
复制
int sharedVal;

您希望您的C代码读取该变量并获取值。简单!只要在范围内阅读它就可以了。您还希望Tcl代码能够写入该变量。简单!在包初始化函数中,放入如下内容:

代码语言:javascript
复制
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变量中获取当前值并进行转换。

如果您希望该变量位于堆中,那么您可以这样做:

代码语言:javascript
复制
int *sharedValPtr = malloc(sizeof(int));

C代码使用*sharedValPtr进行访问,您可以通过以下方式绑定到Tcl:

代码语言:javascript
复制
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 (请参阅文档中的列表),但它们都遵循这种模式。这样,您就可以做到:

代码语言:javascript
复制
char *sharedStr = NULL;
代码语言:javascript
复制
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调用。

票数 2
EN

Stack Overflow用户

发布于 2013-12-11 20:08:31

多纳尔的答案是正确的,但我试着向你展示你的ClientData是怎么做的。

为了说明这一点:所有(或几乎所有)接受函数指针的Tcl函数也都接受ClientData类型的参数,当Tcl调用它时,该参数会传递给函数。

让我们看一下这一行:

代码语言:javascript
复制
Tcl_CreateObjCommand(interp, "mode_thread", mode_thread, NULL, NULL);
// ------------------------------------------------------^^^^

您总是将NULL作为ClientData传递给mode_thread函数。

mode_thread函数中,使用传递的ClientData (NULL)将其作为ClientData传递给新的线程:

代码语言:javascript
复制
limitData = cdata;
// ...
Tcl_CreateThread(&id, mode_service, limitData, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);

mode_service函数中,使用ClientData (仍然是NULL)作为指向char数组的指针:

代码语言:javascript
复制
char* Var = (char *) clientData;

它是指向地址0x00的指针。

然后告诉printf取消引用这个空指针:

代码语言:javascript
复制
printf("%s\n", Var);

这显然会使你的程序崩溃。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/20504705

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档