导致分段错误的TCL\u链接\u字符串(堆芯转储)
我试图与c和tcl共享一个变量,问题是当我试图从tcl读取c线程中的变量时,它会导致分段错误,我不确定这是正确的方法,但它似乎适用于ints。导致分段错误的部分是这一行,当我试图打印“Var”时,但我想读取变量,以便在变量更改时执行相应的操作 这是我正在使用的C代码导致分段错误的TCL\u链接\u字符串(堆芯转储),c,multithreading,tcl,C,Multithreading,Tcl,我试图与c和tcl共享一个变量,问题是当我试图从tcl读取c线程中的变量时,它会导致分段错误,我不确定这是正确的方法,但它似乎适用于ints。导致分段错误的部分是这一行,当我试图打印“Var”时,但我想读取变量,以便在变量更改时执行相应的操作 这是我正在使用的C代码 void mode_service(ClientData clientData) { while(1) { char* Var = (char *) clientData; printf("%s\n", Var);
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_LinkVar
,因此您需要决定链接到哪种类型的变量。如果存储、C访问模式和声明的语义类型之间不匹配,就会导致崩溃
因为您的代码太复杂了,我无法准确地理解您想要做什么,所以我将用不太密切相关的示例进行说明。您需要从他们那里了解如何更改代码中的内容以获得所需的结果
链接整数变量
让我们做一个简单的例子:一个全局int
变量(在任何函数之外声明)
您希望您的C代码读取该变量并获取值。容易的!只要在范围内阅读即可。您还希望Tcl代码能够写入该变量。容易的!在package initialization函数中,输入以下内容:
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\u 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\u LINK INT
(请参阅列表的文档),但它们都遵循这种模式,但除了TCL\u LINK\u STRING
。有了这些,你就可以:
char *sharedStr = NULL;
您还需要注意的是,字符串将始终使用Tcl_Alloc
(对于典型的Tcl内存使用模式,它比大多数系统内存分配器快得多)分配,而不使用任何其他内存分配器,因此也将始终使用Tcl_Free
解除分配。实际上,这意味着如果从C端设置字符串,则必须使用Tcl\u Alloc
来分配内存
发布更新通知
最后一点需要注意的是,当您从C端设置变量,但希望Tcl注意到已经设置了更改(例如,因为设置了
trace
,或者因为您已经在Tk GUI中显示了值),您应该执行Tcl\u updatelinkdvar
,让Tcl知道发生了一个它应该注意的更改。如果您从未使用跟踪(或Tk GUI,或vwait
命令)监视变量的更新,则可以忽略此API调用。Donal的回答是正确的,但我尝试向您展示您对ClientData所做的操作
澄清一下:采用函数指针的所有(或几乎所有Idk)Tcl函数也采用ClientData
类型的参数,该参数在Tcl调用函数时传递给函数
让我们看看这一行:
Tcl_CreateObjCommand(interp, "mode_thread", mode_thread, NULL, NULL);
// ------------------------------------------------------^^^^
您总是将NULL
作为ClientData
传递给mode\u线程
函数。在
mode\u-thread
函数中,使用传递的ClientData
(NULL
)将其作为ClientData传递给新线程:
limitData = cdata;
// ...
Tcl_CreateThread(&id, mode_service, limitData, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);
在mode\u service
功能中,您使用ClientData
(仍然为NULL
)作为指向char
数组的指针:
char* Var = (char *) clientData;
它是指向地址的指针0x00
然后告诉
printf
取消对该空指针的引用:
printf("%s\n", Var);
这显然会使您的程序崩溃。如何定义
ClientData
?@BitFiddlingCodeMonkey它是typedef
用于void*
(可以追溯到void*
之前,在编译器中很常见!)并且通常传达了一个承诺,Tcl不会看指针,而是只发送它。我临时将这个问题重命名为“printf(“%s”,NULL)
崩溃我的程序”我对Tcl的混合编程相当陌生,因此,我应该在调用Tcl_CreateObjCommand时传递一个ClientData变量,以便能够在mode_服务中读取变量的addr。?ClientData可以是任何您喜欢的。Tcl刚刚经过。你想怎么做就怎么做,否则你可以忽略它。这取决于您(如果您需要ClientData,您会很高兴它在那里,而不是相反),我唯一想做的就是从C中的mode_服务函数中读取tcl变量“mode”,一旦我能够在变量发生变化时立即读取它,我将根据“mode”的值执行相应的指令。很抱歉,如果代码一团糟,我对tcl/c编程还相当陌生,这只是一个概念证明
limitData = cdata;
// ...
Tcl_CreateThread(&id, mode_service, limitData, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);
char* Var = (char *) clientData;
printf("%s\n", Var);