TCL_LINK_STRING导致分段错误(核心转储)

时间:2013-12-10 20:37:43

标签: c multithreading tcl

我正在尝试与c和tcl共享变量,问题是当我尝试从tcl读取c线程中的变量时,它会导致分段错误,我不确定这是正确的方法它,但它似乎适用于整数。导致分段错误的部分是这一行是当我尝试打印“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"

2 个答案:

答案 0 :(得分:2)

你的代码完全混乱!你需要决定你在做什么,然后做到这一点。特别是,您正在使用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代码从Tcl变量读取之后(直到Tcl_UnlinkVar),当前值将从C变量中获取并转换。

如果您希望该变量在堆上,那么您可以:

int *sharedValPtr = malloc(sizeof(int));

使用*sharedValPtr进行C代码访问,然后使用:

绑定到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_INT(请参阅文档列表),但它们都遵循{em>除之外的TCL_LINK_STRING模式。有了这个,你可以:

char *sharedStr = NULL;
Tcl_LinkVar(interp, "sharedStr", (char *) &sharedStr, TCL_LINK_STRING);

您还需要注意,字符串将始终分配Tcl_Alloc(这比典型的Tcl内存使用模式的大多数系统内存分配器快得多),而不是任何其他内存分配器,因此始终与Tcl_Free取消分配。实际上,这意味着如果您从C端设置字符串,则必须使用Tcl_Alloc来分配内存。

发布更新通知

要注意的最后一件事是,当您从C侧设置变量但希望Tcl注意到更改已设置时(例如,因为已设置trace或因为您已将值显示在一个Tk GUI),你应该Tcl_UpdateLinkedVar让Tcl知道它应该注意的变化。如果您从未使用跟踪(或Tk GUI或vwait命令)来监视变量的更新,则可以忽略此API调用。

答案 1 :(得分:1)

Donal的回答是正确的,但我试图向您展示您对ClientData的所作所为。

澄清:所有(或几乎所有,Idk)带有函数指针的Tcl函数也采用类型为ClientData的参数,当Tcl调用它时,该参数将传递给您的函数。

让我们来看看这一行:

Tcl_CreateObjCommand(interp, "mode_thread", mode_thread, NULL, NULL);
// ------------------------------------------------------^^^^

您始终将NULL作为ClientData传递给mode_thread函数 在mode_thread函数中,您使用传递的ClientDataNULL)将其作为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取消引用这个NULL指针:

printf("%s\n", Var);

这显然会导致你的程序崩溃。