Unverwaltete Zeiger und .Net
-
Hallo zusammen
bin gerade dabei ein kleines Programm in C++.Net zu schreiben. Leider habe ich noch keine grosse erfahrung mit der CLI.
In meinem Programm verwende ich C Funktionen die ich aus einer DLL importiere. In einer Funktionen muss ich einen Zeiger auf ein 64 byte grosses Array übergeben. Wenn ich ein unverwaltetes Array erstelle und den Zeiger übergebe, funktioniert das alles auch wunderbar. Wenn ich nun aber ein Zeiger(Trackinghandle) eines verwaltenden Arrays übergebe erhalte ich logischerweise eine Fehlermeldung des Compilers.
Bis jetzt habe ich das so gelöst:
ich erstelle 2 Arrays und kopiere jeden eizelnen index. Es gibt sicher noch eine bessere Lösung. Ich hoffe mir kann jemand weiterhelfen.bool PicWinUSB::WriteData(array<Byte> ^DataBuffer, Byte PipeID){ ULONG bytesWritten = 0; unsigned char OutputPacketBuffer[64]; if(DataBuffer->Length != 64){ return false; } int sizeOfOutputPacktBuffer = sizeof(OutputPacketBuffer)/sizeof(OutputPacketBuffer[0]); for(int i=0;i<sizeOfOutputPacktBuffer;i++){ OutputPacketBuffer[i] = DataBuffer[i]; } WinUsb_WritePipeUM(MyWinUSBInterfaceHandle, PipeID, &OutputPacketBuffer[0], 64, &bytesWritten, NULL); return true; }
-
Also ich würde das genau so machen, und eben gerade NICHT das managed Array pinnen. Wenns nicht nötig ist -> nicht pinnen. Und für 64 Byte ist's nicht nötig. Bzw. zahlt sich nicht wirklich aus.
Bloss eins würde ich ändern: ich würde das Kopieren nicht mit einer Schleife machen, sondern System.Runtime.InteropServices.Marshal.Copy() verwenden.
-
Wo pinnt er denn ?
Ansonsten würde ich das Pinnen nicht an der größe des Speichers festmachen sondern an der Situation.
-
Danke für die Antworten.
Leider weis ich nicht was genau pinnen bedeutet. Die Methode sollte aber so schnell wie möglich ablaufen, dann ich Daten über ein USB Port streamen und nicht unnötige Zeit brauchen möchte. Wahrscheinlich werde ich das Array noch auf 512 bytes vergrössern. Da mein USB Gerät 4 Enpoints hat, habe ich 4 solche Methoden in meinem Programm.
-
Knuddlbaer schrieb:
Wo pinnt er denn ?
Ansonsten würde ich das Pinnen nicht an der größe des Speichers festmachen sondern an der Situation.
Er pinnt garnicht, und er soll IMO auch nicht.
-
pat81 schrieb:
Danke für die Antworten.
Leider weis ich nicht was genau pinnen bedeutet. Die Methode sollte aber so schnell wie möglich ablaufen, dann ich Daten über ein USB Port streamen und nicht unnötige Zeit brauchen möchte. Wahrscheinlich werde ich das Array noch auf 512 bytes vergrössern. Da mein USB Gerät 4 Enpoints hat, habe ich 4 solche Methoden in meinem Programm.
So schnell wie möglich? Oder so schnell wie sinnvoll?
Hmmm...Die beiden Transitions managed <-> unmanaged und Usermode <-> Kernelmode, und dann wieder retour, werden schon massiv viel Zeit fressen, verglichen mit dem Kopieren eines 64 oder auch 512 Byte Puffers.
Ich weiss auch nicht ob das Pinnen eines 64 oder 512 Byte Puffers wirklich schneller geht als diesen einfach zu kopieren.
Probier's aus.
Was pinnen angeht:
http://msdn.microsoft.com/en-us/library/1dz8byfh(VS.80).aspx
-
Nochwas: es ist in .NET üblich ein Array, nen Start-Offset und ne Länge bei solchen Sachen zu übergeben.
Damit ermöglichst du dem Aufrufer in einigen Situationen performanteren Code zu schreiben. Nämlich z.B. dann, wenn der Aufrufer die Daten bereits irgendwo in einem Array hat, aber nicht ab Offset 0, und/oder die Daten nicht bis zum Ende des Arrays gehen.
Also...:
bool PicWinUSB::WriteData(array<Byte> ^DataBuffer, int Offset, int Count, Byte PipeID) ...
-
@hustbar: Wenn Du managed Zeiger an unmanaged Funktionen übergibst, ist es unerheblich ob DU denkst das es für 64 Byte nötig ist oder nicht.
Es ist IMMER nötig zu pinnen! Wenn Du anderer Meinung bist, dann hast Du das CLR/GC Konzept noch nicht verstanden. Sag mir einen Grund, warum es nicht nötig sein sollte!Und pinnen tut man so:
pin_ptr<Byte> pfirstElement = &OutputPacketBuffer[0]; WinUsb_WritePipeUM(MyWinUSBInterfaceHandle, PipeID, pfirstElement, 64, &bytesWritten, NULL);
Siehe auch: pin_ptr
http://msdn.microsoft.com/en-us/library/1dz8byfh
-
äh..öh..Ok so langsahm verstehe ich was mit pinnen gemeint ist. Dann kann ich mein OutputPacketBuffer also als Member deklarieren(Managed), in der Methode einen pin_ptr darauf erzeugen und diesen dann der Methode übergeben. Funktioniert soweit auch.
Beim beenden der Methode ist der Zeiger ungültigt aber das Array ist wieder verwaltet. Also muss ich mir keine sorgen wegen Speicherlecks machen? Keine freigabe durch delete oder so? Sorry bin noch nicht so mit .Net vertraut.
-
@Jochen Kalmbach:
Nicht wenn du den Puffer in C++/CLI vorher in ein Stack-Basiertes Array kopierst.
Guck dir das Kopfposting hier an, da macht er genau das
-
Sorry, jetzt hab ichs gesehen... das ist aber sehr langsam... auch kopiert er ja byte für byte...
Mit dem pinnen wäre es aber schneller...
-
Bist du sicher dass es mit Pinnen schneller wäre?
Ich nämlich nicht wirklich...
Vor allem wenn man die handgestrickte Kopierschleife mit Marshal.Copy ersetzt.
-
Es kommt immer darauf an, wie lange das Objekt gepinnt bleibt. Aber wenn ich davon ausgehe, dass es relativ kurz ist, dann hast Du eine Operation O(1) (pinnen) im Vergleich zu O(n) (kopieren). Somit ist es für mich klar, was schneller geht.
Und 3 Mal darfst Du raten, was Marshal.Copy macht...