Jag använder ett API (ReadFile) på en asynkront öppnad fil. Som parameter till detta API skicar man bla med en pekare till en minnesbuffert. Eftersom denna kan returnera närsomhelst medför detta att jag inte kan veta när denna börjar använda den bifogade arrayen. Problem uppstår ifall GC börjar möblera om i minnet och denna således kommer att placera inläst information på fel ställe. Ett sätt att lösa problemet är med stackalloc men denna kan dock bara användas lokalt. Saker som allokeras på stacken städas ju när funktionen/processen/tråden terminerar, eller? har jag helt fel? Helt korrekt!! Jag hade nog inte tänkt igenom det där ordentligt... Kan du inte bara kicka igång en tråd som allokerar minnet på stacken och skickar pekaren till API:t o sen somnar tills API:t returnerar? Det finns ett sätt att 'låsa' en klass och dess variables i minnet, men jag kommer inte ihåg hur man gjorde. Jag har för mig att man talar om att en klass är 'unsafe' GC körs lite som den vill, har inget sammanhang med metoder, trådar eller liknande... och om processen dör försvinner hela heapen så varöfr skull den städa om då? Ok, så här har jag gjort: låter som ett mycket bättre alternativ, att sparka upp en ny tråd det vill säga *S* .. sparka upp den och låt den skicka tillbaka ett event så har du full koll *S* Hrmm... det är nästan värre att låsa resurser på heapen, än att sparka upp en ensam tråd till, låsningen av heapen kan skapa fragmenterat minne under en stund... trådar plockas ur en trådpool för processen och är relativt billiga ändå... Ypperligt bra förslag!!stackalloc
Finns det något annat sätt (inte fixed)? När man använt stackalloc, är man själv ansvarig för att sedan "lämna tillbaka" det allokerade minnet, eller tar GC hand om detta, det är ju "unmanaged code"?Sv: stackalloc
Sv: stackalloc
Däremot kvarstår problemet: Jag läser med ReadFile asynkront och jag vill ha kvar arrayen i minnet (på samma ställe!!) till dess att ReadFile gör callback...Sv: stackalloc
Svara gärna, intressant diskussion
/MojjeSv: stackalloc
/johan/Sv: stackalloc
GC'n kör sin collect när den känner att det är dags, bereonde på ett antal parametrar.
Jag föreslår att du skippar API't, då det inte är meningen att man skall använda pekare i .NET.. Möjligheten finns i sk Unsafe block, men de finns där igentligen bara för bakåtkompabilitet, du kan uppnå samma effekt i System.IO klasserna [1].
Vad gäller att låsa saker i GC'n, är det möjligty, men inte att rekommendera. Överhuvudtaget skall man undvika att tala om för GC'n vad den skall göra och itne göra. Enda legala metoden att leka med där torde vara Supressinilize.
DOck kan du låsa varibler med "lock" statement, vet inte hur den låser för GC'n men den låser för access från andra trådar, vilket i teroin borde låsa för GC'n också (iaf för klienter då GC'n by design körs på egen tråd) .. ahr itne testat det här så vet inte om det stämmer, bara antagande ... semester utan vs.net ...
// Patrik
[1] ms-help://MS.NETFrameworkSDK/cpguidenf/html/cpconasynchronousfileio.htmSv: stackalloc
Jag har två alternativ: Antingen använda Readfile (Ja, jag MÅSTE använda den, suck, .NET har inte det stöd för serieportar jag behöver i filströmmarna...) som asynkron och då måste jag låsa minnet till dess att Readfile får för sig att köra callbacken. Denna lösning har jag lagt åt sidan så länge (med hopp om att få superba idéer härifrån), eftersom jag inte kan låsa minnet på det sätt jag vill.
Det jag valde var att köra "Readfile" som synkron och låta en tråd göra det på följande sätt:
<code>
private void SP_ReaderThread()
{
byte[] data = new byte[STD_RECBUFSIZE];
try
{
while(true)
{
m_objSP.Read(data, 0, 1);
RaiseOnComm(data[0]);
}
}
catch(ThreadAbortException e)
{
Debug.WriteLine(this.ToString() + "SP_ReaderThread: Abort exception (" + e.ToString() + "). Quitting.");
}
}
</code>
Det funkar bra nu, men jag är inte riktigt nöjd, eftersom det medför fler trådar i mitt lilla progg...
Har någon förslag på hur man ska läsa från en serieport via .NETens filströmmar så blir jag lycklig. Enlig min erfarenhet går det inte...Sv: stackalloc
som jag förstått det, stöds seriell kommunikation edast via COM Interop än så lägne tyvärr ...
// PatirkSv: stackalloc
Det som kanske inte framgår ovan är att m_objSP.Read gör någonting liknande:
<code>
unsafe
{
fixed (byte* aBytePtr = buffer)
{
return EndRead(BeginRead(buffer, offset, count, null, null));
}
}
</code>
I detta fall är buferten (buffer) låst under hela tiden till dessa att den synkrona länsningen (som görs i BeginRead) är klar.Sv: stackalloc
Sv: stackalloc
>Finns det något annat sätt (inte fixed)?
Allokera minnet från den ohanterade heapen med någon Marshal.Alloc*() funktion.
>När man använt stackalloc, är man själv ansvarig för att sedan "lämna tillbaka" det allokerade minnet, eller tar GC hand om detta, det är ju "unmanaged code"?
Eftersom det ligger på stacken rensas det bort när du returnerar från funktionen.
MSSv: stackalloc
Jag ska prova att använda Marshal.AllocHGlobal(int cb); och se hur väl den fungerar!!
Så länge kör jag med den synkront läsande tråden, den verkar fungera helt ok!