C# gargbage collector & multithreading

Pagina: 1
Acties:
  • 173 views sinds 30-01-2008
  • Reageer

  • Bart B
  • Registratie: Juli 2000
  • Laatst online: 06-04 17:55
Hallo allemaal,

Ik ben nu enige tijd bezig met een C#. Heel erg mooi allemaal, maar ik heb een kleine maar toch ingewikkelde vraag.

Ik heb een class gedefinieerd. Voor iedere instantie van de class draait een thread. Een class wordt van buiten op de normale manier ge-instantieerd, dit werkt allemaal goed.


de code van de class, met een eigen thread
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
    public class BackgroundThread
    {
        private Thread BackThread;

        public BackgroundThread()
        {
            Console.WriteLine("BackgroundThread: new");
            this.BackThread = new Thread(new ThreadStart(this.run));
            this.BackThread.IsBackground=true;
            this.BackThread.Start();
        }

        ~BackgroundThread()
        {
            Console.WriteLine("BackgroundThread: destroy");
            this.BackThread.Abort();
        }

        private void run()
        {
            while(true)
            {
                Console.WriteLine(".");
                Thread.Sleep(500);
            }
        }
    }


code van het object dat dit alles aanroept:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
        static void Main(string[] args)
        {
            BackgroundThread myObject= new BackgroundThread();
            Console.WriteLine("BackgroundThread object created");
            Thread.Sleep(1000);

            myObject = null;
            Console.WriteLine("BackgroundThread object reference removed");

            Thread.Sleep(1000);

            Console.WriteLine("Calling garbage collector");
            GC.Collect();
            GC.WaitForPendingFinalizers();

            Thread.Sleep(10000);

        }



De garbage collector wil mijn object niet opruimen. Dit is logisch, want een instantie van Thread refereert er aan (dit kan je testen door de thread weg te commenten en de test te draaien). Hoe kan ik er nu toch voor zorgen dat de garbage collector deze instantie van het object oppikt?

Wanneer dit echt niet lukt, dan zal ik waarschijnlijk IDisposable moeten implementeren (ook geen ramp), maar als het met de garbage collector zou kunnen zou dit ook heel relaxed zijn (als iemand ooit zijn troep vergeet op te ruimen, wordt het alsnog ooit eens door de garbage collector gedaan.

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:28
En wat als je je BackGroundThread in je finalizer op null zet ?

https://fgheysels.github.io/


  • Bart B
  • Registratie: Juli 2000
  • Laatst online: 06-04 17:55
whoami schreef op maandag 08 augustus 2005 @ 10:16:
En wat als je je BackGroundThread in je finalizer op null zet ?
Ik kan mijn background thread wel op null zetten in de finalizer, maar dat heeft weinig zin als de finalizer niet wordt aangeroepen :)

  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Ik ben altijd erg huiverig om zo maar threads op te starten (kan tot grote problemen leiden als je hierover geen controle hebt en er te veel threads worden aangemaakt). Daarom werk ik liever met een threadpool. Dan is het nu alleen nog kwestie om de threadpool te stoppen.

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 03-05 13:49

Janoz

Moderator Devschuur®

!litemod

In principe vind ik het helemaal niet vreemd dat hij niet wordt opgeruimd. De thread is immers nog bezig met bewerkingen. Ik kan nog wel enkele voorbeelden verzinnen waarin het heel wenselijk is dat een thread waar niet meer naar wordt gerefereerd, ook niet opgeruimt mag worden.

Het opruimen zal waarschijnlijk wel lukken wanneer de thread afloopt doordat je de boolean expressie in de while iets anders laat opleveren.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Ik denk idd net als janoz dat je thread eerst af zal moeten lopen voordat hij door de GC gemarkt wordt voor opruiming.

Dat jij in jou Main je refference verwijderd wil natuurlijk niet zeggen dat er geen refference meer naar is. Zoals je zelf al dacht houd de thread ieder geval een refference bij naar je Run Methode. Zowiezo vind ik het meestal niet netjes om threads af te breken met Abort. Je weet tenslotte nooit waar je thread mee bezig is. Mischien is hij wel net bezig een bestandje aan het wegschrijven en wordt dat halverwege afgebroken.

Je kan beter idd je while( true ) vervangen door while( running ) of iets dergelijks en dan in een andere method je running op false zetten op het moment dat je vindt dat je thread moet stoppen. Je moet dan alleen nog zorgen dat het block van je while lus niet verschrikkelijk lang duurt want dan werkt dat natuurlijk ook niet echt handig

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


  • Bart B
  • Registratie: Juli 2000
  • Laatst online: 06-04 17:55
Janoz schreef op maandag 08 augustus 2005 @ 10:32:
In principe vind ik het helemaal niet vreemd dat hij niet wordt opgeruimd. De thread is immers nog bezig met bewerkingen. Ik kan nog wel enkele voorbeelden verzinnen waarin het heel wenselijk is dat een thread waar niet meer naar wordt gerefereerd, ook niet opgeruimt mag worden.

Het opruimen zal waarschijnlijk wel lukken wanneer de thread afloopt doordat je de boolean expressie in de while iets anders laat opleveren.
Ik vindt het ook helemaal niet vreemd dat hij niet wordt opgeruimd. Het is ook heel logisch. De vraag is nu echter hoe ik de garbage collector kan manipuleren dat hij die thread niet meneemt in bekijken of er gefinalized mag worden. In de finalize routine kan ik namelijk heel netjes de thread doodmaken, zodat aan het eind al mijn spullen mooi opgeruimd zijn.

Volgens jou methode moet ik IDisposable implementeren (waar ik steeds meer aan denk)

  • Bart B
  • Registratie: Juli 2000
  • Laatst online: 06-04 17:55
rwb schreef op maandag 08 augustus 2005 @ 10:40:
Zowiezo vind ik het meestal niet netjes om threads af te breken met Abort.

...

Je kan beter idd je while( true ) vervangen door while( running ) of iets dergelijks en dan in een andere method je running op false zetten op het moment dat je vindt dat je thread moet stoppen.
Die abort zit er in omdat dit een voorbeeld is om mijn probleem te illusteren. In de uiteindelijke code ben ik niet zo suicidaal om een Abort te gebruiken.

die while running zou ik zo graag in de finalize willen doen :'(

  • Janoz
  • Registratie: Oktober 2000
  • Laatst online: 03-05 13:49

Janoz

Moderator Devschuur®

!litemod

die while running zou ik zo graag in de finalize willen doen
De denkfout die je maakt zit juist in die volgorde. De thread wordt niet gestopt omdat hij gefinaleized/disposed wordt, maar kan worden gefinalized/disposed omdat hij gestopt is. Je zult toch ergens aan moeten geven dat de thread moet stoppen. Het opruimen door de gc van lopende code is natuurlijk sowieso not done.

Ken Thompson's famous line from V6 UNIX is equaly applicable to this post:
'You are not expected to understand this'


  • Bart B
  • Registratie: Juli 2000
  • Laatst online: 06-04 17:55
IDisposable implementeren dus. Jmr :(

  • EfBe
  • Registratie: Januari 2000
  • Niet online
een finalizer implementeren zonder IDisposable is natuurlijk sowieso niet nuttig.
Die finalizer moet resources opruimen, niet een thread stoppen. Dus die kan IMHO gewoon weg.

[ Voor 37% gewijzigd door EfBe op 08-08-2005 11:43 ]

Creator of: LLBLGen Pro | Camera mods for games
Photography portfolio: https://fransbouma.com


  • Hydra
  • Registratie: September 2000
  • Laatst online: 26-04 10:16
Ik snap niet helemaal wat het probleem is. Je start een Thread. Als die Thread niet meer nodig is, stop je 'em op de normale manier (hij loopt uit die while loop). Threads stoppen in finalizers e.d. is compleet de verkeerde aanpak, je moet sowieso in normale gevallen met je tengels van de garbage collection afblijven.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class TestThread 
{
    private bool cont;
    
    public void Run() 
    {
        cont = true;
        while(cont)
        {
            doStuff();
        }

    }
    
    public void Stop() 
    {
        cont = false;   
    }
}


Zo hoort 't. Desnoods kun je de Thread interrupten als 'ie perse meteen moet stoppen.

https://niels.nu


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Hydra schreef op dinsdag 09 augustus 2005 @ 17:06:
Zo hoort 't. Desnoods kun je de Thread interrupten als 'ie perse meteen moet stoppen.
Je moet er wel voor zorgen dat die conditie als volatile veld wordt gedeclareerd omdat je anders de kans loopt dat alleen de register waarde wordt uitgelezen en niet de waarde die in het geheugen staat. Als je dit niet doet, loop je de kans dat de thread niet gaat stoppen.

dus:
private volatile bool cont;

voor meer informatie: http://msdn.microsoft.com...ef/html/vclrfvolatile.asp

[ Voor 18% gewijzigd door Alarmnummer op 09-08-2005 17:41 ]


  • Hydra
  • Registratie: September 2000
  • Laatst online: 26-04 10:16
Alarmnummer schreef op dinsdag 09 augustus 2005 @ 17:39:
Je moet er wel voor zorgen dat die conditie als volatile veld wordt gedeclareerd omdat je anders de kans loopt dat alleen de register waarde wordt uitgelezen en niet de waarde die in het geheugen staat. Als je dit niet doet, loop je de kans dat de thread niet gaat stoppen.
Tuurlijk. Zelf doe ik 't altijd met locks, maar dat komt vooral omdat Java geen 'volatile' kent. Het ging me d'r hier om dat 'ie geen threads moet gaan aborten in een finalizer. Objecten worden sowieso niet meteen gegarbagecollect.

https://niels.nu


  • Alarmnummer
  • Registratie: Juli 2001
  • Laatst online: 09-07-2024

Alarmnummer

-= Tja =-

Hydra schreef op dinsdag 09 augustus 2005 @ 17:47:
Tuurlijk. Zelf doe ik 't altijd met locks, maar dat komt vooral omdat Java geen 'volatile' kent.
Heb jij zeker een andere versie van Java dan ik :P Vanaf 1.5 wordt jsr133 officieel ondersteund en vanaf 1.4 officieus. Maar daar zat (zo ver ik het weet) dus ook al een correct werkende volatile in.

Ik werk op een of andere manier bijna nooit op deze manier met threads terwijl ik er toch behoorlijk veel mee doe. Trouwens.. een AtomicBoolean is ook een optie (scheelt weer lock-code).
Het ging me d'r hier om dat 'ie geen threads moet gaan aborten in een finalizer. Objecten worden sowieso niet meteen gegarbagecollect.
Yep.. en verder uiteraard de vraag of dit object, omdat het draait, uberhaubt in aanmerking komt om ge-gc`ed te worden.

[ Voor 3% gewijzigd door Alarmnummer op 09-08-2005 17:54 ]


  • Hydra
  • Registratie: September 2000
  • Laatst online: 26-04 10:16
Alarmnummer schreef op dinsdag 09 augustus 2005 @ 17:53:
Heb jij zeker een andere versie van Java dan ik :P Vanaf 1.5 wordt jsr133 officieel ondersteund en vanaf 1.4 officieus. Maar daar zat (zo ver ik het weet) dus ook al een correct werkende volatile in.
De java versie van onze OO API is 1.2 compatible, en de laatste versie waar ik mee gewerkt heb is 1.3 vandaar :) Ik doe tegenwoordig eigenlijk alles in C# :)
Alarmnummer schreef op dinsdag 09 augustus 2005 @ 17:53:
Yep.. en verder uiteraard de vraag of dit object, omdat het draait, uberhaubt in aanmerking komt om ge-gc`ed te worden.
Nou, dat sowieso niet. Gelukkig :) Dit vond ik ook wel grappig:
Console.WriteLine("Calling garbage collector");
GC.Collect();
GC.WaitForPendingFinalizers();

GC.Collect() hint naar de GC dat je het wel fijn zou vinden als 'ie garbage gaat collecten. Maar er is geen enkele garantie (integendeel) dat alles ge-GCed wordt.

[ Voor 38% gewijzigd door Hydra op 10-08-2005 10:00 ]

https://niels.nu

Pagina: 1