Momentan arbeite ich an dem Schreiben eines C# -Skripts, das in Julia-Modulen geschriebene Funktionen aufrufen kann. Julia bietet eine C-API, mit der Funktionen in Julia aufgerufen werden können. Ich habe es geschafft, Funktionen zu bekommen, die in Julia-Modulen geschrieben wurden, um von C# aus aufgerufen zu werden und Array-Daten zu erhalten, die hin und her gereicht werden.Julia in C# einbetten: Garbage Collector in C# umwandeln Fragen und Fragen
Allerdings bin ich mir nicht ganz sicher, wie man den Garbage Collector korrekt steuert. Dieser Code ist der von julia.h bereitgestellte Inlinecode, der dem Garbage Collector von Julia mitteilt, dass die Variablen, auf die durch Argumente verwiesen wird, in einem anderen Skript verwendet werden und nicht verschoben/freigegeben werden sollten. Jeder Anruf (jl_gc_push()
oder jl_gc_push_args()
drückt etwas auf den Stapel, die die Garbage Collector verwendet
-Code in 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
gibt eine Struktur, die einen Zeiger namens pgcstack
Ich glaube, das ist die Sache, die die Garbage Collector verwendet. arg1
sollte vom Typ seine jl_value_t*
und rts_var
sollte jl_value_t**
vom Typ sein.
Frage 1:
ich diesen besonderen Unterschied zwischen dieser Linie in JL_GC_PUSH1 nicht vereinbaren kann (und die anderen JL_GC_PUSH # ist):
void *__gc_stkf[] = {(void*)3, ...
und diese Linie in JL_GC_PUSHARGS:
((void**)rts_var)[-2] = (void*)(((size_t)(n))<<1);
Wenn ich JL_GC_PUSH1 verwendet, um dem Garbage Collector mitzuteilen, dass eine Variable ignoriert werden soll, würde die erste Variable im Array auf 3 gesetzt. Wenn ich JL_GC_PUSHARGS verwenden würde, würde sie es auf 2 setzen. Ich dachte Bit Verschiebung nach links gefüllt mit Nullen? Ich verstehe, wie alles andere in diesen Funktionen funktioniert.
Frage 2: Ich schreibe eine C# Funktion das tut, was JL_GC_PUSHARGS tut, außer es in params IntPtr
statt jl_value_t**
nimmt. Ist es sicher, wenn ich Speicher wie diesen zuteile? Weiß jemand, ob Julia die Zuweisung aufheben wird, oder werde ich Marshal anrufen müssen? FreeHGlobal auf die Erinnerung? Wenn Julia es trotzdem tut und ich Marshal anrufe. Freeh Global, wird es Probleme geben?
C# Version:
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 ^^
}
Für nimmt jetzt nur, dass jl_pgcstack()
auf die Inline-Funktion in C geschrieben entspricht Ich habe Probleme damit, aber das ist ein anderes Problem.
Während es prinzipiell möglich ist, ist das Einhängen direkt in den GC-Stack wahrscheinlich nicht ideal. Eine andere Möglichkeit, mit dem Julia GC zu interagieren, besteht darin, Referenzen in ein globales Array zu pushen. Das macht Pyjulia ([via PyCall] (https://github.com/JuliaPy/PyCall.jl/blob/1d755f27fd440a43b9a792919fee0531495754e0/src/pytype.jl#L433-L440)), und siehe auch die [eng verwandte Diskussion] (https://docs.julaulang.org/en/latest/manual/calling-c-and-fortran-code/#Garbage-Collection-Safety-1) im Hauptteil des Handbuchs. Hoffentlich ist das genug, um loszulegen. –