myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
   » Plugin für Firefox
   » Plugin für IE
   » Gadget für Windows
» Regeln
» Wie poste ich richtig?
» Datenschutzerklärung
» wbb-FAQ

Mitglieder
» Liste / Suche
» Stadt / Anleitung dazu
» Wer ist wo online?

Angebote
» ASP.NET Webspace
» Bücher
» Zeitschriften
   » dot.net magazin

Ressourcen
» guide to C#
» openbook: Visual C#
» openbook: OO
» MSDN Webcasts
» Search.Net

Team
» Kontakt
» Übersicht
» Wir über uns
» Impressum

» Unsere MiniCity
MiniCity
» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Entwicklung » Rund um die Programmierung » Bug in LightCore? (ThreadSingletonLifecycle)
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

Bug in LightCore? (ThreadSingletonLifecycle)

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
mouk
myCSharp.de-Mitglied

Dabei seit: 09.08.2010
Beiträge: 9


mouk ist offline

Bug in LightCore? (ThreadSingletonLifecycle)

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo zusammen,

in der Klasse ThreadSingletonLifecycle habe ich den folgenden Bug entdeckt.

Objekte mit dem o.g. LiftCycle werden, nachdem der Thread terminiert wurde, nicht freigegeben. Habe dazu den Folgenenden Unittest gebastelt:

C#-Code (Test):
[TestMethod()]
public void ThreadSingletonShouldBecollectedwhenThreadFinished()
{
    var builder = new ContainerBuilder();
    builder.Register<IDo, Do>().ControlledBy<ThreadSingletonLifecycle>();
    var container = builder.Build();
    WeakReference obj = null; ;
    Action action = () =>
    {
        var o = container.Resolve<IDo>();
        obj = new WeakReference(o);
    };

    var thread = new Thread(new ThreadStart(action));
    thread.Start();
    thread.Join();
    Assert.IsTrue(obj.IsAlive);
    thread = null;
    GC.Collect(2);
    Assert.IsFalse(obj.IsAlive, "Objekt sollte nicht mehr existieren");
}

C#-Code (Interfaces):
public interface IDo{}

public class Do : IDo{}

Dies liegt daran, dass die Objekte in einem Dictionary gespeichert werden, das für die gesamte Lebenszeit des Containers erhalten bleibt. Dies kann man lösen, indem man das Objekte als static markiert und mit der Attribute [ThreadStatic] versieht.



Viele Grüße,

Mouk
09.08.2010 17:14 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
zero_x zero_x ist männlich
myCSharp.de-Mitglied

images/avatars/avatar-2567.gif


Dabei seit: 16.02.2008
Beiträge: 1.044
Herkunft: Koblenz


zero_x ist offline Füge zero_x Deiner Kontaktliste hinzu

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo mouk,

action muss auch null sein, damit der GC keine Referenzen auf obj bzw. die Instanz von Do hat.

zero_x
09.08.2010 17:25 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
mouk
myCSharp.de-Mitglied

Dabei seit: 09.08.2010
Beiträge: 9

Themenstarter Thema begonnen von mouk

mouk ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

action enthält nur einen Verweis auf container, was aber nicht schlimm ist. o ist nur eine lokale Variable, die bei jedem Aufruf angelegt wird und danach sofort zum GCen freigegeben wird.

Obj ist eine WeakReference. D.H. die hindert dem GC nicht daran, ihren Inhalt zu löschen (Das ist die einzige Aufgabe von WeakReference: Einen Verweis auf ein Objekt liefern, solange dieses Objekt noch lebt).

Von daher ist der Test korrekt.

Mouk

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von mouk am 09.08.2010 17:47.

09.08.2010 17:44 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Peter Bucher Peter Bucher ist männlich
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-2785.jpg


Dabei seit: 17.03.2005
Beiträge: 5.872
Entwicklungsumgebung: VS08
Herkunft: Zentralschweiz


Peter Bucher ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo mouk

Der Bug ist gefixt und ins SVN Repository eingecheckt.
Wenn alle bekannte Bugs gefixt worden sind, gibt es einen neuen Release.

Fixed ThreadSingleton does not release references after thread exit bug.
see: ( Bug in LightCore? (ThreadSingletonLifecycle)).

Beschreibung:
Ich habe das Problem so gelöst, das Lifecycle-intern nicht das Object (object) referenziert wird (Im Dictionary gehalten), sondern eine WeakReference davon.

Das wars schon :-)


Gruss Peter
19.08.2010 03:00 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
mouk
myCSharp.de-Mitglied

Dabei seit: 09.08.2010
Beiträge: 9

Themenstarter Thema begonnen von mouk

mouk ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Peter,

danke für den Bug-fix. Ich glaube jedoch, dass jetz die Singleton-Eigenschaft verletzt wird.

Falls du zweie Methoden hast, M1() und M2(), die jeweils

container.Resolve<Object>(); aufrufen, dann gibt es keine Garantie mehr, dass sie das gleiche Objekt bekommen, auch wenn sie im gleichen Thread laufen. Nach dem Aufruf von M1() könnte der GC anspringen und das Objekt entfernen. Der M2()-Aufruf (oder ein weiter M1-Aufruf ) würde ein neues Objekt bekommen.

Außerdem müsste man jetzt einen Prozess regelmäßig starten, der die toten WeaklReferences aus dem Dictionary entfernt (und dabei das Dictionary auch lockt).

Das Dictionary folgendermaßen definieren

C#-Code:
[ThreadStatic]
private static Dictionary<Type, Object> _dictionary = new ..;

würde das problem einfach lösen.
19.08.2010 12:30 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Peter Bucher Peter Bucher ist männlich
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-2785.jpg


Dabei seit: 17.03.2005
Beiträge: 5.872
Entwicklungsumgebung: VS08
Herkunft: Zentralschweiz


Peter Bucher ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo mouk

Das ursprüngliche Beispiel ist in meinen Augen fehlerhaft.
Wenn die Variable als Thread-affines Singleton definiert wird, ist es ja per se verboten, diese in mehr als zwei Threads zu nutzen.

Wenn Du das - per Tricks wie hier mit einer Captured Variable - doch machst, hebelst Du die Eigenschaft der Thread-Affinität aus und "missbrauchst" LightCore ja quasi. Dass das nicht funktioniert, ist klar.

Ist in meinen Augen aber kein Bug, weil falsche Voraussetzungen gegeben sind.

(Wenn ich auf ein Objekt in einer WeakReference noch eine zusätzliche Referenz halte, wird das auch nicht richtig abgeräumt - da kann die WeakReference dann aber auch nichts für ;))

Auch ist es in meinen Augen nicht klar, ob der Thread mit dem Setzen auf null und einem Absetzen von GC.Collect(2) wirklich abgeräumt wird.

Ein Thread.Abort() würde diese Aufgabe vermutlich sauberer lösen.

In meinen Augen ist das kein offensichtlicher Fehler, da das Beispiel relativ konstruiert ist und das fehlende Abräumen von Instanzen nicht direkt als Fehler sichtbar ist.


Gruss Peter
21.08.2010 22:04 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
mouk
myCSharp.de-Mitglied

Dabei seit: 09.08.2010
Beiträge: 9

Themenstarter Thema begonnen von mouk

mouk ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Peter,

das Beispiel ist natürlich konstruiert, es soll ja nur den Bug demonstrieren und nicht die best practices vorstellen. (Trotzdem ist es nicht verboten, eine ThreadSingle Variablen in einem fremden Thread zu verwenden, es mach nur i.d.R keinen Sinn)

Bei diesem Bug handelt es sich einfach darum, dass instanziiere Objekte nicht freigegeben werden, nachdem der dazugehörige Thread terminiert wurde.

Die captured Variable dient einfach der Demonstration. Du kannst das fehlerhafte Verfahren beobachten, indem du eine Instanz in einem neuen Thread holst, den Thread terminiert und dann in einem Profiler den Speicher untersuchen analysiert, oder einfach in der Klasse Do einen Verweis auf ein 200 MB großes Array verwalten und nach dem Aufruf von DC.Collect dir den Speicherverbrauch in dem Task-Manager anschaust. Daraus lässt sich aber kein Unitest ableiten.

Thread.Abort() ist an dieser Stelle, meiner Meinung nach, nicht wichtig, da Thread.Join aufgerufen wurde. Damit ist der Zustand des Threads Stopped. Man kann aber trotzdem Abort() zusätzlich aufrufen, ändert auch nichts am Ergebnis.

Gruß,

Mouk

P.S. ich hab den exakten Unitest erfolgreich mit StructureMap ausgeführt. Man könnte sich weitere IoC Containers anschauen.
22.08.2010 00:59 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 7 Jahre.
Der letzte Beitrag ist älter als 7 Jahre.
Antwort erstellen


© Copyright 2003-2018 myCSharp.de-Team. Alle Rechte vorbehalten. 24.01.2018 12:49