Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Tcl和C线程的动态共享内存空间_C_Multithreading_Tcl - Fatal编程技术网

Tcl和C线程的动态共享内存空间

Tcl和C线程的动态共享内存空间,c,multithreading,tcl,C,Multithreading,Tcl,我希望在Tcl和C线程之间有一个动态共享内存空间 线程共享内存空间的大小是在运行xxx_Init(Tcl_Interp*Interp){…}过程时分配的,但我想根据Tcl变量为其分配一个空间,以优化内存使用 可能吗?若有,如何处理 编辑:提供的详细代码显示了我想做什么和我的问题 指向包含共享数据的结构的指针将作为客户端数据与名为testCmd的过程共享,该过程在两个Tcl变量之后分配内存空间大小。它还作为客户端数据与新创建的线程共享。下面详细介绍了C扩展,但它不起作用,因为内存空间不是在线程之间

我希望在Tcl和C线程之间有一个动态共享内存空间

线程共享内存空间的大小是在运行
xxx_Init(Tcl_Interp*Interp){…}
过程时分配的,但我想根据Tcl变量为其分配一个空间,以优化内存使用

可能吗?若有,如何处理

编辑:提供的详细代码显示了我想做什么和我的问题

指向包含共享数据的结构的指针将作为客户端数据与名为
testCmd
的过程共享,该过程在两个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 ;
}
代码的输出给出(如果产生错误的零件是否被注释):


在_Init函数中有一个参数是Tcl_Interp*。因此,您应该能够使用Tcl_Eval或其变体在解释器中执行一些Tcl代码。然后,您应该能够运行一个Tcl proc,比如返回您想要的值,然后使用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 

因此,每次调用test时,都会根据要测试的前两个参数的值重新分配内存。

请注意,您必须将数据复制到该空间中或从该空间中复制出来;Tcl的值内存管理不能直接处理共享内存块本身的约束。那么参数1和参数2从何而来呢?它们是在Tcl解释器中定义的吗?行应该是:sharedData*sDataPtr;不是varList*sDataPtr?事实上,这是最新的。抱歉,这个问题太麻烦了……如果parameter1和PARAMETER2刚刚定义好,那么问题出在哪里;你知道这些价值观。好的,这是个好主意。但是,我希望
Tcl_Eval
中的变量名是一个参数,并且内存空间大小要在特定的Tcl命令上重新分配。如果我将指向内存空间的指针作为ClientData传递给C扩展函数,是否可以修改它所指向的内存空间,并且在退出函数时不释放该空间?我不确定你的第一个问题是什么意思,你什么时候知道变量名是什么,以及它作为参数传递给你什么?如果将一些ClientData传递给Tcl_CreateCommand(),则该值在实现该命令的C代码中可用,并保留到使用Tcl_DeleteCommand删除该命令为止。因此,如果ClientData指向指向已分配空间的内存位置,那么您可以根据需要重新分配空间,而无需更改ClientData—另一种间接指向指针的指针。事实上,它是有效的,我已经这样做了,但是
dH
共享内存空间可以在线程之间共享吗?我稍后会尝试,但我不认为它会起作用,因为内存空间不是全局的…我们已经有点偏离了你最初的问题,那就是将参数1/2数据输入到你的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 ;
}
load basicTclExtn.dll
puts [BasicExtnCmd 10 12]
test 1 2
test 3 4