Tcl_CreateInterp 怎么会陷入死循环呢?
How can Tcl_CreateInterp end up in an inifinite loop?
我正在使用 Tcl 库版本 8.6.4(使用 Visual Studio 2015,64 位编译)来解释来自 C/C++ 程序的一些 Tcl 命令。
我注意到如果我从不同的线程创建解释器,第二个会以无限循环结束:
#include "tcl.h"
#include <boost/thread.hpp>
#include <boost/filesystem.hpp>
void runScript()
{
Tcl_Interp* pInterp = Tcl_CreateInterp();
std::string sTclPath = boost::filesystem::current_path().string() + "/../../stg/Debug/lib/tcl";
const char* setvalue = Tcl_SetVar( pInterp, "tcl_library", sTclPath.c_str(), TCL_GLOBAL_ONLY );
assert( setvalue != NULL );
int i = Tcl_Init( pInterp );
assert( i == TCL_OK );
int nTclResult = Tcl_Eval( pInterp, "puts \"Hello\"" );
assert( nTclResult == TCL_OK );
Tcl_DeleteInterp( pInterp );
}
int main( int argc, char* argv[] )
{
Tcl_FindExecutable(NULL);
runScript();
runScript();
boost::thread thrd1( runScript );
thrd1.join(); // works OK
boost::thread thrd2( runScript );
thrd2.join(); // never joins
return 1;
}
这里是无限循环,在 Tcl 源代码中:
void
TclInitNotifier(void)
{
ThreadSpecificData *tsdPtr;
Tcl_ThreadId threadId = Tcl_GetCurrentThread();
Tcl_MutexLock(&listLock);
for (tsdPtr = firstNotifierPtr; tsdPtr && tsdPtr->threadId != threadId;
tsdPtr = tsdPtr->nextPtr) {
/* Empty loop body. */
}
// I never exit this loop because, after first thread was joined
// at some point tsdPtr == tsdPtr->nextPtr
我做错了什么吗?是否缺少任何特殊函数调用?
注意:TCL_THREADS
在我编译 Tcl 时没有设置。但是,我觉得我在这里没有做错任何事。另外,添加
/* Empty loop body. */
if ( tsdPtr != NULL && tsdPtr->nextPtr == tsdPtr )
{
tsdPtr = NULL;
break;
}
循环内显然解决了这个问题。但是我对修改3rd party library源码不是很有信心...
向 Tcl 团队报告 bug 后,我被要求再次尝试使用启用 TCL_THREADS
编译的 Tcl 库。它解决了这个问题。
TCL_THREADS
被禁用是因为我使用在网上找到的 CMake Lists.txt
文件在 windows 上编译:这个文件实际上是为 Linux 编写的并且禁用了线程支持因为它无法在我的机器上找到 pthread
。我最终使用 Tcl 团队提供的脚本编译了 Tcl 库:默认启用线程,无限循环消失了!
我正在使用 Tcl 库版本 8.6.4(使用 Visual Studio 2015,64 位编译)来解释来自 C/C++ 程序的一些 Tcl 命令。
我注意到如果我从不同的线程创建解释器,第二个会以无限循环结束:
#include "tcl.h"
#include <boost/thread.hpp>
#include <boost/filesystem.hpp>
void runScript()
{
Tcl_Interp* pInterp = Tcl_CreateInterp();
std::string sTclPath = boost::filesystem::current_path().string() + "/../../stg/Debug/lib/tcl";
const char* setvalue = Tcl_SetVar( pInterp, "tcl_library", sTclPath.c_str(), TCL_GLOBAL_ONLY );
assert( setvalue != NULL );
int i = Tcl_Init( pInterp );
assert( i == TCL_OK );
int nTclResult = Tcl_Eval( pInterp, "puts \"Hello\"" );
assert( nTclResult == TCL_OK );
Tcl_DeleteInterp( pInterp );
}
int main( int argc, char* argv[] )
{
Tcl_FindExecutable(NULL);
runScript();
runScript();
boost::thread thrd1( runScript );
thrd1.join(); // works OK
boost::thread thrd2( runScript );
thrd2.join(); // never joins
return 1;
}
这里是无限循环,在 Tcl 源代码中:
void
TclInitNotifier(void)
{
ThreadSpecificData *tsdPtr;
Tcl_ThreadId threadId = Tcl_GetCurrentThread();
Tcl_MutexLock(&listLock);
for (tsdPtr = firstNotifierPtr; tsdPtr && tsdPtr->threadId != threadId;
tsdPtr = tsdPtr->nextPtr) {
/* Empty loop body. */
}
// I never exit this loop because, after first thread was joined
// at some point tsdPtr == tsdPtr->nextPtr
我做错了什么吗?是否缺少任何特殊函数调用?
注意:TCL_THREADS
在我编译 Tcl 时没有设置。但是,我觉得我在这里没有做错任何事。另外,添加
/* Empty loop body. */
if ( tsdPtr != NULL && tsdPtr->nextPtr == tsdPtr )
{
tsdPtr = NULL;
break;
}
循环内显然解决了这个问题。但是我对修改3rd party library源码不是很有信心...
向 Tcl 团队报告 bug 后,我被要求再次尝试使用启用 TCL_THREADS
编译的 Tcl 库。它解决了这个问题。
TCL_THREADS
被禁用是因为我使用在网上找到的 CMake Lists.txt
文件在 windows 上编译:这个文件实际上是为 Linux 编写的并且禁用了线程支持因为它无法在我的机器上找到 pthread
。我最终使用 Tcl 团队提供的脚本编译了 Tcl 库:默认启用线程,无限循环消失了!