1

私はtclスクリプトを実行するプログラムを書いています。スクリプトにexitコマンドがある場合、プログラムはこのエラーでクラッシュします

DeleteInterpProc called with active evals
Aborted

ここで、 scriptTcl_EvalFile(m_interpreter, script.c_str())はファイル名です。また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_Releaseの後に、Tcl_Interpハンドルが削除されたメモリを参照する場合があることに注意してください。(はい、 RAIIの良さでTcl_Preserve/をラップするのTcl_Releaseは合理的です。)


代わりに、スクリプトの実行後にコードの実行を許可する場合は、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のマニュアルページですが、少なくとも20年以上前のTcl 7.0以降、関連するルールは当てはまります。)インタプリタが削除されると、コマンドの実行やその中の変数へのアクセスを期待できなくなります。Tclライブラリは、状態の巻き戻しを処理します。

于 2013-03-04T15:42:22.320 に答える
1

コマンドを置き換え(非表示)して、プログラムを正常に終了するexit独自のコマンドを作成する方がよい場合があります。exit私はCとTclCApiがあまり得意ではありませんが、これがお役に立てば幸いです。

たとえば、Eggdropはdieコマンドを使用して正常に終了します。

于 2013-03-06T19:38:32.333 に答える