0

Tcl と C スレッドの間に動的な共有メモリ スペースが必要です。

そのスレッド共有メモリ スペースのサイズは、xxx_Init (Tcl_Interp *interp) {...}プロシージャの実行時に割り当てられますが、メモリの使用を最適化するために、Tcl 変数に応じてスペースを割り当てたいと考えています。

出来ますか?はいの場合、どうすればよいですか?

編集:私がやりたいことと私の問題を示す詳細なコードが提供されました。

共有データを含む構造体へのポインタは、testCmd2 つの Tcl 変数に続いてメモリ空間サイズを割り当てるプロシージャが呼び出され、クライアント データとして共有されます。また、新しく作成されたスレッドでクライアント データとして共有されます。C 拡張については以下で詳しく説明しますが、メモリ空間がスレッド間で共有されておらずxxx_Init (Tcl_Interp *interp) {...}、プロシージャで定義する必要があるため、機能しません。しかし、そうすると、割り当てるメモリ空間のサイズを指定する Tcl の変数を取得できません。

    #include <tcl.h>

typedef struct dataHandle_ {
    char *data ;
    long p1 ;
    long p2 ;
} dataHandle_T ;

// Thread function
// Test if we can write memory space allocated by 'testCmd0' function
static void startRoutine (ClientData clientData) {
    dataHandle_T *dH = (dataHandle_T *) clientData;
    //test
    FILE *file;
    file=fopen("testFile.txt", "w");
    while (1) { 
        int mul=dH->p1*dH->p2;
        if (mul<10) {
            dH->data="A";
        } else {
            dH->data="Large str";
        }
        fprintf(file, "Memory size is %d, word is %s ", mul, dH->data);
    }
    fclose(file);
}


// Test command
// Allocating a new memory space for thread shared memory, depending on 2 Tcl variables values
int testCmd(
    ClientData data,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *CONST objv[])
{
    dataHandle_T *dH = (dataHandle_T *)data ;

    // Check the number of arguments
    if (objc != 3) {
        Tcl_WrongNumArgs(interp, 1, objv, "arg arg");
        return TCL_ERROR;
    }

    long p1, p2, result ;

    if ( Tcl_GetLongFromObj(interp, objv[1], &p1) != TCL_OK)
        return TCL_ERROR ;

    if ( Tcl_GetLongFromObj(interp, objv[2], &p2)  != TCL_OK)
        return TCL_ERROR ;

    // Is a re-allocation needed?
    if (dH->p1 != p1 || dH->p2 != p2) {
        if (dH->data != NULL)
            Tcl_Free(dH->data) ;
        dH->data = Tcl_Alloc(p1 * p2 * sizeof(char)) ;// Or whatever allocation you need
    }

    return TCL_OK ;

}

// Create thread launching startRoutine procedure with a dataHandle_T as argument
createThread_Cmd(
    ClientData cdata,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *const objv[])
{

    // Contain 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);

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


// Note the casing on the _Init function name
int DLLEXPORT

Test_Init(Tcl_Interp *interp)
{
    // Link with the stubs library to make the extension as portable as possible
    if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
        return TCL_ERROR;
    }

    // Declare which package and version is provided by this C code
    if ( Tcl_PkgProvide(interp, "BasicTclExtn", "1.0") != TCL_OK ) {
        return TCL_ERROR ;
    }

    // Allocate the storage for the ClientData
    dataHandle_T *hD = (dataHandle_T *)Tcl_Alloc(sizeof(dataHandle_T));

    // Initialise the new structure
    hD->data = NULL ;
    hD->p1 = -1 ;
    hD->p2 = -1 ;

    // Create a command
    Tcl_CreateObjCommand(interp, "test", testCmd, (ClientData)hD, (Tcl_CmdDeleteProc *)NULL);
    Tcl_CreateObjCommand(interp, "createThread", createThread_Cmd, (ClientData)hD, NULL);
    return TCL_OK ;
}

次の Tcl コードを実行すると、次のようになります。

load [file join [pwd] libtest[info sharedlibextension]]
test 1 2

set threadId [createThread]
puts "Created thread $threadId"
after 500
# ==Produce an error==
test 4 3
after 500
test 10 20
# =====
exit 1

コードの出力は次のようになります (エラーを生成する部分がコメント化されているかどうかにかかわらず):

$ tclsh test.tcl
Created thread -1227109568
$ tclsh test.tcl
Created thread -1227019456
alloc: invalid block: 0x431abb: 69 2e
Aborted (core dumped)
4

1 に答える 1

2

_Init 関数に含める 1 つのパラメーターは Tcl_Interp* です。したがって、これにより、Tcl_Eval またはそのバリアントの 1 つを使用して、そのインタープリターでいくつかの Tcl コードを実行できるはずです。その後、必要な値を返す Tcl プロシージャを実行し、Tcl_GetObjResult() を使用して Interp から値を取得できるはずです。

次のコードは、_Init 関数で機能します。

int res ;
if ( Tcl_Eval(interp, "set myVal") != TCL_OK)
    return TCL_ERROR ;

if (Tcl_GetIntFromObj(interp,Tcl_GetObjResult(interp), &res) != TCL_OK)
    return TCL_ERROR ;

次の Tcl スクリプトを使用します。

set myVal 102
load basicTclExtn.dll

値 102 は、最終的に C++ res 変数になります。

編集とコメントに基づいて、次のコードになりました。これで問題が解決されることを願っています。

まず、Tcl C 拡張機能

typedef struct dataHandle_ {
    char *data ;
    long p1 ;
    long p2 ;
} dataHandle_T ;

// Test command
int testCmd(
    ClientData data,
    Tcl_Interp *interp,
    int objc,
    Tcl_Obj *CONST objv[])
{
    dataHandle_T *dH = (dataHandle_T *)data ;

    // Check the number of arguments
    if (objc != 3) {
        Tcl_WrongNumArgs(interp, 1, objv, "arg arg");
        return TCL_ERROR;
    }

    long p1, p2, result ;

    if ( Tcl_GetLongFromObj(interp, objv[1], &p1) != TCL_OK)
        return TCL_ERROR ;

    if ( Tcl_GetLongFromObj(interp, objv[2], &p2)  != TCL_OK)
        return TCL_ERROR ;

    // Is a re-allocation needed?
    if (dH->p1 != p1 || dH->p2 != p2) {
        if (dH->data != NULL)
            Tcl_Free(dH->data) ;
        dH->data = Tcl_Alloc(p1 * p2 * sizeof(char)) ;// Or whatever allocation you need
    }

    return TCL_OK ;

}

// Note the casing on the _Init function name
BASICTCLEXTN_API int Basictclextn_Init(Tcl_Interp *interp)
{
    // Link with the stubs library to make the extension as portable as possible
    if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
        return TCL_ERROR;
    }

    // Declare which package and version is provided by this C code
    if ( Tcl_PkgProvide(interp, "BasicTclExtn", "1.0") != TCL_OK ) {
        return TCL_ERROR ;
    }

    // Allocate the storage for the ClientData
    dataHandle_T *hD = (dataHandle_T *)Tcl_Alloc(sizeof(dataHandle_T));

    // Initialise the new structure
    hD->data = NULL ;
    hD->p1 = -1 ;
    hD->p2 = -1 ;

    // Create a command
    Tcl_CreateObjCommand(interp, "test", testCmd, (ClientData)hD, (Tcl_CmdDeleteProc *)NULL);

    return TCL_OK ;
}

そして、Tclスクリプト

load basicTclExtn.dll
puts [BasicExtnCmd 10 12]
test 1 2
test 3 4 

したがって、テストする最初の 2 つのパラメーターの値に基づいてテストが呼び出されるたびに、メモリが再割り当てされます。

于 2012-09-20T13:57:40.100 に答える