alloc:invalid block – 对于每个线程的线程Tcl / 1 interp,Tcl_IncrRefCount和Tcl_DecrRefCount线程是否安全?

我们的32位服务器应用程序静态嵌入tcl 8.4.11。 在Red Hat Linux 6.5 64位上,我们遇到崩溃/核心转储。 失败的样子

alloc:无效块:0xf6f00f58:88 f6 0

在问题的底部,我记录了我们见过的两个不同的核心转储。

我们已经将潜在的根本原因隔离到两个线程之间共享的TCL对象,并同时运行单独的TCL解释器实例。 我们认为这是因为TCL对象从这些并发执行的TCL解释器传递给Tcl_IncrRefCount / Tcl_DecrRefCount。

  1. 当TCL编译为线程时,Tcl_IncrRefCount / Tcl_DecrRefCount线程是否安全?
  2. TCL对象是否由TCL解释器实例共享? 有没有办法在解释器实例之间禁用TCL对象共享?
  3. 在TCL版本8.6.3中情况有所改善吗?
(gdb) bt #0 __kernel_vsyscall () at arch/x86/vdso/vdso32/sysenter.S:49 #1 0x001b7871 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 #2 0x001b914a in abort () at abort.c:92 #3 0x080f611c in Tcl_PanicVA () #4 0x080f613b in Tcl_Panic () #5 0x0810133c in Ptr2Block () #6 0x08100e04 in TclpFree () #7 0x080b46a7 in Tcl_Free () #8 0x08100686 in FreeStringInternalRep () #9 0x080fdac1 in ResetObjResult () #10 0x080fd316 in Tcl_GetStringResult () #11 0x0808aaad in run_tcl_proc (pDevice=0x8e0ba08, pInterp=0x8d798c0, iNumArgs=2, objv=0x115434c, bIsCommand=0 '\000', pCommand=0x0) #12 0x08093672 in Tcl_begin_next_state (pDevice=0x8e0ba08, iNextState=RunPoll, pCommand=0x0) #13 0x08093759 in Tcl_port_thread (dummy=0x8d1cab8) #14 0x008bcb39 in start_thread (arg=0x1154b70) at pthread_create.c:301 #15 0x0026fc2e in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:133 (gdb) 
 (gdb) bt #0 __kernel_vsyscall () at arch/x86/vdso/vdso32/sysenter.S:49 #1 0x00395871 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 #2 0x0039714a in abort () at abort.c:92 #3 0x080f611c in Tcl_PanicVA () #4 0x080f613b in Tcl_Panic () #5 0x0810133c in Ptr2Block () #6 0x08100e04 in TclpFree () #7 0x080b46a7 in Tcl_Free () #8 0x080d21b6 in TclExecuteByteCode () #9 0x080d1bc1 in TclCompEvalObj () #10 0x080fbd5c in TclObjInterpProc () #11 0x080b026a in TclEvalObjvInternal () #12 0x080d2716 in TclExecuteByteCode () #13 0x080d1bc1 in TclCompEvalObj () #14 0x080fbd5c in TclObjInterpProc () #15 0x080b026a in TclEvalObjvInternal () #16 0x080b0517 in Tcl_EvalObjv () #17 0x0808aa02 in run_tcl_proc (pDevice=0x94a2500, pInterp=0xac2bba0, iNumArgs=2, objv=0x11b034c, bIsCommand=0 '\000', pCommand=0x0) #18 0x08093672 in Tcl_begin_next_state (pDevice=0x94a2500, iNextState=RunPoll, pCommand=0x0) #19 0x08093759 in Tcl_port_thread (dummy=0x9365e98) #20 0x00356b39 in start_thread (arg=0x11b0b70) at pthread_create.c:301 #21 0x0044dc2e in clone () at ../sysdeps/unix/sysv/linux/i386/clone.S:133 (gdb) 

调用Tcl_IncrRefCount (实际上是一个简单的宏)和Tcl_DecrRefCount (一个复杂的宏)是一种线程安全的,但只是因为每个Tcl_Obj只能从创建它的线程中访问; 对T_IRC和T_DRC的并行调用很好,只要它们处于不同的值即可。 这方面的优点是访问不需要锁定(并且Tcl_Obj结构的内存管理器利用了这一点)。

请注意,除非您非常小心,否则multithreading访问根本不是一个好的计划,因为如果需要应用类型转换,即使像Tcl_GetIntFromObj这样的读取器操作也可以写入底层结构。 这些操作未锁定。 完全这样做需要非常了解当前的值类型 – 而不是通常鼓励您在Tcl中首先考虑的事情,尽管tcl::unsupported::representation可能有助于在8.6中进行探讨 – 并且线程之间有一些非常小心的互锁,这样一个人不会在另一个人偷看时写字。 完全不这样做 ,虽然不是100%准确,但是最不可能导致头痛的方法。

您可能应该阅读更多关于您应该如何做的事情。 ActiveState博客有一个合理的介绍。