1

我正在编写一个执行 tcl 脚本的程序。当脚本有exit命令时,程序会因为这个错误而崩溃

DeleteInterpProc called with active evals
Aborted

我正在调用Tcl_EvalFile(m_interpreter, script.c_str())where script 是文件名。我也尝试过Tcl_Eval使用参数解释器和“源文件名”。结果是一样的。其他 tcl 命令(例如 puts)解释器正常执行。如何解决这个问题?

#include <tcl.h>
#include <iostream>

int main() {
    Tcl_Interp *interp = Tcl_CreateInterp(); 

    //Tcl_Preserve(interp);

    Tcl_Eval (interp, "exit");

    //Tcl_Release(interp);

    std::cout << "11111111111" << std::endl;

    return 0;
}

这是简单的情况。不打印“11111111111”。据我了解,调用Tcl_Eval (interp, "exit");. Tcl_Preserve添加和后的结果是一样的Tcl_Release

4

2 回答 2

3

问题在于解释器,即 Tcl 代码的执行上下文,正在从自身下面删除它的脚;这让人很困惑!至少你得到了一个干净的恐慌/中止,而不是一个令人作呕的难以重现的崩溃。

最简单的解决方法可能是:

Tcl_Preserve(m_interpreter);
// Your code that calls Tcl_EvalFile(m_interpreter, script.c_str())
// and deals with the results.
Tcl_Release(m_interpreter);

请注意,在 之后Tcl_ReleaseTcl_Interp句柄可能指的是已删除的内存。(是的,将Tcl_Preserve/包裹Tcl_Release在 RAII 中是合理的。)


如果您希望在脚本执行 之后允许您的代码运行exit,您必须采取额外的步骤。特别是,标准的 Tclexit命令并非旨在导致返回到调用上下文:它将导致进程调用_exit(2)系统调用。要更改其行为,请将其替换:

// A callback function that implements the replacement
static int
MyReplacementExit(ClientData unused, Tcl_Interp *interp, int argc, const char *argv[])
{
    // We ought to check the argument count... but why bother?
    Tcl_DeleteInterp(interp);
    return TCL_OK;
}

int main() {
    Tcl_Interp *interp = Tcl_CreateInterp(); 

    // Install that function over the standard [exit]
    Tcl_CreateCommand(interp, "exit", MyReplacementExit, NULL, NULL);

    // Important; need to keep the *handle* live until we're finished
    Tcl_Preserve(interp);

    // Or run whatever code you want here...
    Tcl_Eval(interp, "exit");

    // Important piece of cleanup code
    if (!Tcl_InterpDeleted(interp))
        Tcl_DeleteInterp(interp);
    Tcl_Release(interp);
    // After this point, you *MUST NOT* use interp

    std::cout << "11111111111" << std::endl;
    return 0;
}

在这些场景中进行内存管理的规则Tcl_CreateInterp. (那是 8.6 的手册页,但至少从 Tcl 7.0 开始,相关规则就一直是正确的,这已经是 2 多年前了。)一旦删除了解释器,您就不能再指望执行任何命令或访问其中的任何变量;Tcl 库为您处理状态展开。

于 2013-03-04T15:42:22.320 回答
1

exit替换(隐藏)命令并创建自己的exit命令以优雅地退出程序可能会更好。我不太擅长 C 和 Tcl C Api,但我希望这可以帮助你。

例如 Eggdrop 使用die命令优雅地退出。

于 2013-03-06T19:38:32.333 回答