Laden...

[gelöst] Zugriff auf Variable welche in einem Hintergrund-Thread geladen wird

Erstellt von Froggie vor 12 Jahren Letzter Beitrag vor 12 Jahren 1.129 Views
F
Froggie Themenstarter:in
323 Beiträge seit 2007
vor 12 Jahren
[gelöst] Zugriff auf Variable welche in einem Hintergrund-Thread geladen wird

Hallo!

Ich habe da mal eine Frage zu einer Best-Practice.

Ich habe 2 BOs (A und B) und A hat ein Property mit einer Auflistung von mehreren Bs).
Im konstruktor von A wird ein Thread gestartet (aus dem ThreadPool) welcher das Property befüllt/initialisiert. In diesem Thread werden die einzelnen Bs geladen un der Auflistung hinzugefügt. Somit sind sie beim Zugrif auf die Auflistung bereits vorhanden (die Daten werden also bereits im Hintergrund geladen für bessere Performance).

Nun zu meinem Problem.
Wenn ich auf die Auflistung zugreife, obwohl der thread sie noch nicht gefüllt hat bekomme ich eine leere Auflistung zurück. Das ist ja ein unerwünschter Effekt des Ladens im Hintergrund.
Mein Ansatz wäre folgender:
In A gibt es eine Variable "bereits geladen" welche default auf "nein" steht. Der Thread zum Laden setzt diese Variable am Ende auf "ja".
Beim Zugriff auf die auflistung wird geprüft ob "bereits geladen" auf "ja" steht. Falls nicht dann warte ich mittels Thread.Sleep(100) bis es auf "ja" steht.

Ist das so gängige Best-Practice oder gibt es bessere Varianten? Mich stört konkret das Thread.Sleep, aber mir fällt eben keine bessere Möglichkeit ein.

B
198 Beiträge seit 2005
vor 12 Jahren

Kannst du dir keinen Event bauen, der gefeuert wird, sobald der Thread fertig ist mit der Initialisierung?

S
417 Beiträge seit 2008
vor 12 Jahren

Hallo,

also im Konstruktor Threads zu starten finde ich nicht grade gut, aber ist hier nicht das Thema.
Du kannst AutoResetEvent verwenden:

public class A
{
	private AutoResetEvent ev = new AutoResetEvent(false);
	private List<object> bList;

	public A()
	{
		// Threads
		ThreadPool...(callback_methode);
	}

	void callback_methode()
	{
		bList = ...
		ev.Set();
	}

	public List<object> Bs
	{
		get
		{
			ev.WaitOne();
			return bList;
		}
	}
}
F
10.010 Beiträge seit 2004
vor 12 Jahren

Beim Zugriff auf die auflistung wird geprüft ob "bereits geladen" auf "ja" steht. Falls nicht dann warte ich mittels Thread.Sleep(100) bis es auf "ja" steht.

Und wozu dann überhaupt ein Thread, wenn du im anderen warten willst?
Wenn du einen UI Thread entlasten willst, dann feuere ein Event nach Abschluss des Lesevorgangs.

6.900 Beiträge seit 2009
vor 12 Jahren

Hallo Froggie,

In A gibt es eine Variable "bereits geladen" welche default auf "nein" steht.

Das ist gar nicht nötig, denn es kann auf != null geprüft werden und das liefert dasselbe Ergebnis.

Ich würde einfach bei A INotifyPropertyChanged implementieren und wenn die Bs geladen sind das PropertyChanged-Event feuern. In der UI ist die Auswahlmöglichkeit der Bs disabled solagen sie nicht geladen sind od. es wird eine leere Liste angezeigt. Erst wenn sie geladen sind, wird duch das PropertyChanged benachrichtigt, wird die Asuwahl enabled.

mfG Gü

Stellt fachliche Fragen bitte im Forum, damit von den Antworten alle profitieren. Daher beantworte ich solche Fragen nicht per PM.

"Alle sagten, das geht nicht! Dann kam einer, der wusste das nicht - und hat's gemacht!"

F
Froggie Themenstarter:in
323 Beiträge seit 2007
vor 12 Jahren

Aufgrund der Rahmenbedingungen habe ich die Lösung von Sarc probiert.
Diese funktioniert bei mir ausgezeichnet.

Ich musste nur eine Kleinigkeit anpassen.


ev.WaitOne(10, true);

Vielen Dank nochmal!

656 Beiträge seit 2008
vor 12 Jahren

Nur kurz am Rande, was spricht gegen eine BindingList oder eine ObservableCollection? Beide sagen dir Bescheid, wenn sich Items geändert haben; somit kann das GUI entsprechend drauf reagieren (über ListChanged bzw. CollectionChanged).
Der Background-Thread fügt einfach jedes Item ein, was er geladen hat, anstatt drauf zu warten bis alles fertig ist (Hinweis: eventuell bekommst du hier auch wieder Probleme beim Zugriff von verschiedenen Threads, dafür kannst du aber die Forensuche benutzen - gab schon genug Beiträge zu den Punkten).
Je nachdem, ob du auf der anderen Seite sogar WPF hast, sollte das ganze auch ohne größere Umbauten automagically funktionieren.

49.485 Beiträge seit 2005
vor 12 Jahren

Hallo Froggie,

wenn ich es richtig verstehe, geht es letztlich darum, die Daten im GUI anzuzeigen. Dann ist aber WaitOne tabu, weil sonst das GUI blockiert.

Sicher kann man sagen, geht doch die Klasse nichts an, dass ihre Daten im GUI angezeigt werden sollen. Das ist nicht ganz falsch, aber man muss ja für den Benutzer der Klasse auch keine unnötigen Fallstricke einbauen.

Dazu kommt was FZelle andegeutet hat, dass es sowieso wenig Sinn macht, eine Aktion in einen anderen Thread zu verlagern und dann im ursprünglichen Thread darauf zu waren, bis die Aktion fertig ist.

Eine Lösung über Events (ob nun eigene oder die von passenden fertigen Klasse sei mal dahingestellt) ist wesentlich sinnvoller.

herbivore