2012-07-09 8 views
8

Ich muss einen verwalteten Rückruf an einen nicht verwalteten TCP-Empfänger übergeben. Da es ein Thread ist, der für die Lebensdauer der Anwendung vorhanden sein muss, muss ich verhindern, dass der Müll gesammelt wird. Ich habe überall gelesen, dass Pinning Funktion Pointer nicht erforderlich ist und GCHandle.Alloc wird die Aufgabe, Garbage Collection zu verhindern.Pin einen Funktionszeiger

Aber ist das gegeben? Ich habe gesehen, dass der AppPool, der diesen Code hostet, mit einer Zugriffsverletzung abstürzt. Warum sollte ich nicht die Tatsache vermuten, dass dieser Fehler auftritt, weil der Funktionszeiger "Garbage Collection" war? Diese post unterstützt diese Tatsache.

Update: Dies scheint die Abstürze erheblich reduziert zu haben. Gibt es ein Problem mit diesem Ansatz?

typedef void (__cdecl *ProcMessageFunc)(void* param, void* paramBuf, ULONG bufSize); 
FuncDelegate^ fp = gcnew MessageFuncDelegate(this, &Handler); 
pin_ptr<MessageFuncDelegate^> pinnedFunctionPointer = &fp; 
ret = Receiver ((ProcMessageFunc)pinnedFunctionPointer); 
+3

Das Delegate-Objekt in einer statischen Variablen zu speichern ist ausreichend. Nativer Code kann aus vielen anderen Gründen mit Zugriffsverletzungen bombardieren. –

+0

Ich habe genau das getan. Der Grund, warum ich dazu tendiere, die Garbage Collection als Ursache zu verdächtigen, ist, dass die Zugriffsverletzung unregelmäßig auftritt. Und noch wichtiger ist der Aufruf-Stack im Crash-Dump Ich kann die native DLL sehen, gefolgt von der clr.dll und dann kernel32.dll an der Spitze des Stapels. Diese Reihenfolge ist konsistent. – Krishter

Antwort

8

ich tun genau das, was Sie zu tun vorschlagen - GCHandle.Alloc auf den Delegaten, aber ohne Pinning - und habe keine Probleme in umfangreichen Einsatz auf vielen verschiedenen Plattformen hatte und auf .NET-Versionen 2.0 - 4. Etwas wie:

DelegateHandle = GCHandle.Alloc(xlDelegate); 
FunctionPointer = Marshal.GetFunctionPointerForDelegate(xlDelegate); 

mit FunctionPointer ging dann zu dem nativen Code und DelegateHandle für eine spätere Bereinigung gehalten.

Dies scheint die beste Referenz zu sein: http://msdn.microsoft.com/en-us/library/367eeye0(v=vs.80).aspx.

Nichts in der Post, den Sie diesen Hinweis auf Widerspruch hinweisen - Sie müssen die Delegierten aus der Garbage Collection zu schützen, es ist nur, dass Pinning nicht erforderlich ist.

+0

Ist das Adress-Pinning für Funktionen nicht notwendig, da sie im Gegensatz zu Heap-Objekten an einer konstanten Stelle existieren? Welche Adresse hat eine Funktion, wenn sie noch nicht gejittet wurde? – Dai

+2

Ich denke, der Aufruf von GetFunctionPointerForDelegate erstellt einen kleinen Marshalling-Stub, der einen festen Einstiegspunkt hat, aber wenn der Delegat verschoben wird, wird der Stub immer noch wissen, wie es aufgerufen wird. Der exportierte Funktionszeiger ist also kein direkter Export der Adresse des Delegate-Objekts (im Gegensatz zu einem gepinnten Array oder Strukturelement). Denken Sie daran, dass die exportierte "native" Funktion auch den nativen -> verwalteten Übergang implementieren muss. – Govert

+0

Genau das habe ich gemacht. Leider tritt die Zugriffsverletzung immer noch auf. Lassen Sie es mich so sagen. Wie kann ich absolut sicher sein, dass dies nicht die Ursache für die Zugriffsverletzung ist? – Krishter