将Julia嵌入C#:垃圾收集器将C#问题和问题改写为问题



当前我正在努力编写一个可以调用朱莉娅模块编写的函数的c#脚本。朱莉娅(Julia(提供了允许在朱莉娅(Julia(中调用功能的C API。我设法获得了用朱莉娅模块编写的功能,要从c#调用,并获得来回传递的数组数据。

但是,我不确定如何正确控制垃圾收集器。该代码是> Julia.h 提供的内联代码,该代码告诉朱莉娅垃圾收集器,args指向的变量被用在另一个脚本中,不应移动/交易。每个调用(jl_gc_push()jl_gc_push_args()将一件东西推到垃圾收集器使用的堆栈中。

Julia.h中的代码:

#define jl_pgcstack (jl_get_ptls_states()->pgcstack)
#define JL_GC_PUSH1(arg1)               
    void *__gc_stkf[] = {(void*)3, jl_pgcstack, arg1};     
    jl_pgcstack = (jl_gcframe_t*)__gc_stkf;
...(similar functions for 2, 3, 4)............
#define JL_GC_PUSH5(arg1, arg2, arg3, arg4, arg5)        
    void *__gc_stkf[] = {(void*)11, jl_pgcstack, arg1, arg2, arg3, arg4, arg5};              
    jl_pgcstack = (jl_gcframe_t*)__gc_stkf;
#define JL_GC_PUSHARGS(rts_var,n)                     
    rts_var = ((jl_value_t**)alloca(((n)+2)*sizeof(jl_value_t*)))+2;   
    ((void**)rts_var)[-2] = (void*)(((size_t)(n))<<1);              
    ((void**)rts_var)[-1] = jl_pgcstack;                 
    memset((void*)rts_var, 0, (n)*sizeof(jl_value_t*));        
    jl_pgcstack = (jl_gcframe_t*)&(((void**)rts_var)[-2])
#define JL_GC_POP() (jl_pgcstack = jl_pgcstack = jl_pgcstack->prev)

jl_get_ptls_states返回一个指针,称为pgcstack。我相信这就是垃圾收集器使用的东西。arg1应该是jl_value_t*类型,rts_var应该为jl_value_t**类型。

问题1:

我无法调和JL_GC_PUSH1中此行之间的特定差异(以及其他JL_GC_PUSH#and(:

void *__gc_stkf[] = {(void*)3, ...

和jl_gc_pushargs中的这一行:

((void**)rts_var)[-2] = (void*)(((size_t)(n))<<1);

如果我使用jl_gc_push1告诉垃圾收集器,我希望忽略一个变量,它将将数组中的第一个变量设置为3。但是,如果我使用jl_gc_pushargs,它将设置为2。想到有点移动到左侧的零?我了解这些功能中其他所有功能的工作原理。

问题2:我正在编写一个C#函数,该功能可以执行JL_GC_PUSHARGS所做的工作,但它采用params IntPtr而不是jl_value_t**。如果我这样分配记忆,是否安全?有谁知道朱莉娅是否会根据需要进行交易,还是我必须在记忆中打电话给元帅。如果朱莉娅(Julia(无论如何都会称呼元帅。freehglobal,会有问题吗?

C#版本:

public unsafe static void JL_GC_PUSHARGS(params IntPtr[] args) {
        int l = args.Length;
        IntPtr* pgcstacknew = (IntPtr*) Marshal.AllocHGlobal(Marshal.SizeOf<IntPtr>() * (l + 2)).ToPointer();
        pgcstacknew[0] = (IntPtr)(2 * l + 1); //related to Question 1
        pgcstacknew[1] = jl_pgcstack();
        for(uint i = 2; i < l + 2; i++){
            pgcstacknew[i] = args[i - 2];
        }
        jl_pgcstack() = pgcstacknew;
        //I'm still having issues with this line ^^  
    }

现在只假设jl_pgcstack()等于C.我有问题的内联函数,但这是一个不同的问题。

问题1

JL_GC_PUSH1JL_GC_PUSHARGS宏具有不同的堆栈布局。低位表示它是哪一个。

问题2

朱莉娅(Julia(不会对任何东西进行交易,因为创建GC框架时不应该分配任何东西。如果您要分配,通常最好通过Julia API并在ObjectIdDict之上构建模拟的REF计数方案(JL_EQTABLE_GET/PUT(。

JL_GC_PUSHARGS的直接翻译应该看起来像:

unsafe {
    // JL_GC_PUSHARGS
    uint l = args.Length;
    IntPtr* pgcstacknew = stackalloc IntPtr[l + 2];
    pgcstacknew[0] = (IntPtr)(l << 2); // how many roots?
    pgcstacknew[1] = jl_pgcstack(); // link to previous gc-frame
    for (uint i = 0; i < l; i++) { // copy the args to the stack roots
        pgcstacknew[i + 2] = args[i];
    }
    jl_pgcstack() = pgcstacknew; // install frame at top of gc-stack
}
// <do stuff with args here>
unsafe {
    // JL_GC_POP
    jl_pgcstack() = pgcstacknew[1]; // remove frame from gc-stack
}

另一种选择是使用jl_call集合的功能,其中包括GC帧的设置和拆卸(以及异常帧(。

最新更新