gpt4 book ai didi

c - Tcl 和 C 线程之间的共享变量

转载 作者:太空宇宙 更新时间:2023-11-04 04:00:29 25 4
gpt4 key购买 nike

我有一个 Tcl 主程序,我想从中创建一个 C 线程。然后我需要在两个线程之间共享信息:C 线程的进程经常更新输入/输出。我看到我的问题有两种可能的解决方案: (1) 将 Tcl 的线程共享变量移植到 C,但我没有在 TCL-C API 中看到任何关于它的信息。 (2) 创建 Tcl-C 链接变量并在 C 线程创建期间将其用作参数。后一种想法似乎行不通。这是 C 代码:

#include <tcl.h>

/*
startRoutine
*/
static void startRoutine (ClientData clientData) {
int *Var;
Var= (int *) clientData;
int locA=0;
int j;
int k;
while (1) {
if (locA=!*Var) {
// Modify Tcl-C shared variable
locA=2 * *Var;
*Var=locA;
for (j=0; j<100; j++){}
} else {
for (k=0; k<100; k++){}
}
}
}




static int
createThreadC_Cmd(
ClientData cdata,
Tcl_Interp *interp,
int objc,
Tcl_Obj *const objv[])
{

// Contains the ID of the newly created thread
Tcl_ThreadId id;
// Thread argument
ClientData limitData;

// Transfering global var argument to the created thread
limitData=cdata;

// Thread creation
id=0;
Tcl_CreateThread(&id, startRoutine, limitData, TCL_THREAD_STACK_DEFAULT, TCL_THREAD_NOFLAGS);

// Wait thread process, before returning to TCL prog
int i;
int aa;
for (i=0 ; i<10000000 ; i++){
aa=i;
}

// Return thread ID to tcl prog to allow mutex use
Tcl_SetObjResult(interp, Tcl_NewIntObj((int) id));
return TCL_OK;
}


int DLLEXPORT

Behavcextension_Init(Tcl_Interp *interp)
{

if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}

// Create global Var
int *sharedPtr;
int linkedVar=0;
sharedPtr=&linkedVar;
Tcl_LinkVar(interp, "linkedVar", (char *) sharedPtr, TCL_LINK_INT);

Tcl_CreateObjCommand(interp,
"createThreadC", createThreadC_Cmd, sharedPtr, NULL);
return TCL_OK;

}

这是 Tcl 代码:

# linkedVar initial value in Tcl, will be overwritten by C Tcl_LinkVar() function
set linkedVar 98
puts "linkedVar: $linkedVar"

# Thread creation
#------------------
load [file join [pwd] libBehavCextension[info sharedlibextension]]
set threadId [createThreadC]
puts "Created thread $threadId, waiting"
# When Tcl_LinkVar() is called, initiate linkedVar at 2
puts "linkedVar: $linkedVar"

# Function inside thread should modify linkedVar into linkedVar*2
set linkedVar 98
after 5000
puts "linkedVar: $linkedVar"

终端输出在这里:

Main thread ID: tid0xb779b6c0
linkedVar: 98
Created thread -1227252928, waiting
linkedVar: 2
linkedVar: 98

最后的结果应该是2*98=196。 Tcl 和 C 之间的 LinkVar 创建是可以的(链接创建后我们得到 2),但是将 LinkVar 传递给 Thread 是 KO。欢迎任何关于为什么它不起作用/如何解决它的解决方案或解释!

最佳答案

问题和另一个问题一样。您在一个函数中为 C 端的 C 堆栈上的变量分配存储空间,该函数随后不久终止。在函数 (Behavcextension_Init) 终止后引用该变量(Behavcextension_Init 中的 linkedVar)是未定义行为。实际发生的情况是,实际存储用于其他一些函数调用(谁知道做什么),因此包含的值是任意的,更改它会导致“令人兴奋”的行为。

您希望在 Behavcextension_Init 完成后存在一个变量,因此它不能分配到该函数的堆栈中。最简单的方法是这样的:

int DLLEXPORT
Behavcextension_Init(Tcl_Interp *interp)
{
int *sharedPtr;

if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}

sharedPtr = (int *) Tcl_Alloc(sizeof(int)); // Allocate
*sharedPtr = 0; // Initialize
Tcl_LinkVar(interp, "linkedVar", (char *) sharedPtr, TCL_LINK_INT);

Tcl_CreateObjCommand(interp,
"createThreadC", createThreadC_Cmd, sharedPtr, NULL);
return TCL_OK;
}

注意事项

  1. 这会泄漏内存,因为没有与 Tcl_Alloc 匹配的 Tcl_Free。对于每个进程分配一次的内存,这不是什么大问题。毕竟,它只有几个字节,操作系统会在退出时回收它。
  2. 当从与写入变量的线程不同的线程读取变量时,这是不安全的;根本无法保证它会起作用。它可能可以工作,因为它只是一个整数,但您需要依赖硬件才能协作。 正确的做法是分配一个包含变量和合适的互斥锁的结构,并使用互斥锁保护对变量的访问(无论是读还是写)。这反过来又要求您不使用 Tcl_LinkVar — 它对互斥保护内存一无所知 — 但 Tcl_LinkVar 只是 Tcl_TraceVar 的包装器提供一个回调函数,在 Tcl 的变量(参见 Tcl_GetVarTcl_SetVar)和 C 变量之间进行耦合;自己编写一个知道如何进行互斥保护处理的程序并不难。 (如果您有兴趣,请获取 source to Tcl_LinkVar 并自行调整;它不使用任何私有(private) API 调用。)

关于c - Tcl 和 C 线程之间的共享变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12348599/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com