2012-07-09 16 views
8

Devo passare un callback gestito a un ricevitore TCP non gestito. Poiché è un thread che deve esistere per tutta la durata dell'applicazione, è necessario impedirgli di ottenere i dati raccolti. Ho letto ovunque che i puntatori di funzione di pinning non sono richiesti e GCHandle.Alloc farà il lavoro di prevenzione della garbage collection.Pin un puntatore di funzione

Ma è un dato? Ho visto che l'AppPool che ospita questo codice si arresta in modo anomalo con una violazione di accesso. Perché non dovrei sospettare il fatto che questo errore si verifica perché il puntatore della funzione è stato garbage collocato?

Questo post supporta questo fatto.

Aggiornamento: Questo sembra aver ridotto notevolmente i crash. C'è un problema con questo approccio?

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

È sufficiente memorizzare l'oggetto delegato in una variabile statica. Il codice nativo può bombardare con violazioni di accesso per molti altri motivi. –

+0

Ho fatto esattamente questo. Il motivo per cui tendo a sospettare che la garbage collection sia la causa è che la violazione di accesso si verifica in modo errato. E, ancora più importante, lo stack di chiamate nel crash dump posso vedere la dll nativa seguita dal clr.dll e quindi dal kernel32.dll in cima allo stack. Questo ordine è coerente. – Krishter

risposta

8

io fare esattamente quello che suggeriscono di fare - GCHandle.Alloc sulla delegato ma senza pinning - e non ho avuto alcun problema a un uso estensivo su molte diverse piattaforme e sulle versioni di .NET 2.0 - 4. Qualcosa come:

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

con FunctionPointer poi passato al codice nativo, e DelegateHandle mantenuto per la pulizia dopo.

Questo sembra essere il miglior riferimento: http://msdn.microsoft.com/en-us/library/367eeye0(v=vs.80).aspx.

Nulla nel post che si punta a contraddire questo riferimento - è necessario proteggere il delegato dalla garbage collection, è solo che il blocco non è richiesto.

+0

Il blocco degli indirizzi per le funzioni non è necessario perché, a differenza degli oggetti heap, esistono in una posizione const? Quale indirizzo ha una funzione se non è stata ancora JIT? – Dai

+2

Penso che la chiamata a GetFunctionPointerForDelegate crea un piccolo stub di marshalling con un punto di accesso fisso, ma se il delegato viene spostato, lo stub saprà comunque come chiamarlo. Quindi il puntatore a funzione esportata non è un'esportazione diretta dell'indirizzo dell'oggetto delegato (diversamente da un array a pin o un membro struct). Ricorda che la funzione 'nativa' esportata deve anche implementare la transizione nativa -> gestita. – Govert

+0

Questo è esattamente quello che ho fatto. Sfortunatamente la violazione di accesso si verifica ancora. Lasciami dire così. Come posso essere perfettamente sicuro che questa NON sia la causa della violazione di accesso? – Krishter

Problemi correlati