Laden...

Synchronisierungsproblem abhängiger Threads (Backgroundworker)

Erstellt von yamukud vor 12 Jahren Letzter Beitrag vor 12 Jahren 1.146 Views
Y
yamukud Themenstarter:in
22 Beiträge seit 2009
vor 12 Jahren
Synchronisierungsproblem abhängiger Threads (Backgroundworker)

Hallo ihr Lieben,

ich möchte von euch kurz wissen, ob meine Einschätzung korrekt ist.

Zur zu erledigenden Aufgabe: Ein Thread liest eine größere CSV-Datei ein und verarbeitet diese. Dies wird am Anfang der Applikation ausgeführt, da der Vorgang ca. 2 Sekunden dauert und sowieso einige Forms durchgeklickt werden müssen.

Der Code der aufgerufenen Methode des Singletonobjekts:

public void CreateNewDocIDTable()
        {
            _docIdTable = null;
            if (bw != null && bw.IsBusy)
            {
                bw.CancelAsync();
                while (bw.IsBusy)
                {
                    Thread.Sleep(50);
                }
            }
            try
            {
                bw.RunWorkerAsync();
            }
            catch (Exception ex)
            {
                string s = ex.Message;
            }
        }

Die Initialisierung des BackgroundWorkers:

            bw = new System.ComponentModel.BackgroundWorker();
            bw.DoWork += new System.ComponentModel.DoWorkEventHandler(bw_DoWork);
            bw.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);

Das Abholen des erstellten Objekts:

        public Table DocIdTable
        {
            get
            {
                    return _docIdTable;
            }
            set
            {
                    _docIdTable = value;
            }
        }

Nun muss ich also sicherstellen, dass das Objekt bereits erstellt ist, wenn es abgerufen wird. Auf den Thread warten (if (_docIdTable == null) Thread.Sleep(xxx)) ist unschön und funktioniert auch nicht: Die bw_RunWorkerCompleted-Methode wird nicht mehr aufgerufen.

Rein fachlich wäre ein Warten auf den Thread bei dieser Applikation sogar i.O., einen praktikablen Weg sehe ich aber nicht.

Benötige ich hier das Observer-Muster?

Danke,
Liebe Grüße,
yamukud

5.742 Beiträge seit 2007
vor 12 Jahren

Nun muss ich also sicherstellen, dass das Objekt bereits erstellt ist, wenn es abgerufen wird.

Baue deine Anwendung lieber so um, dass der Abruf erst aufgrund von RunWorkerCompleted erfolgt (indem die Form z.B. erst dort geöffnet wird).

Thread.Sleep deutet in 99% der Fälle auf eine sehr suboptimale Lösung hin.

Y
yamukud Themenstarter:in
22 Beiträge seit 2009
vor 12 Jahren

Hallo Winsharp,

würde ich es aus der RunWorkerCompleted-Methode heraus erlauben, die nächste Form aufzurufen, hätte ich keinen Vorteil dazu, die CSV-Datei erst bei Arbeitsbeginn zu laden. Nur der Ort des Wartens hat sich verschoben.

Und wie beschrieben funktioniert Thread.Sleep sowieso nicht (RunWorkerCompleted-Methode wird nach dem Durchlaufen der DoWork-Methode nicht aufgerufen).

Liebe Grüße,
yamukud

Nachtrag: Meine einzige Idee wäre eben den Arbeitsbeginn zu blockieren, bis ein Event ankommt, dass das Objekt geladen wurde. Es verursacht aber eine unschöne Architektur, das Singletonobjekt soll "stand-alone" funktionieren.

49.485 Beiträge seit 2005
vor 12 Jahren

Hallo yamukud,

im GUI-Thread darfst du nicht warten, siehe [FAQ] Warum blockiert mein GUI?

Du musst also die Aktion, die die Daten verarbeiten soll, erstmal abbrechen, wenn die Daten noch nicht vorhanden sind und sie später wieder neu starten, z.B. per Timer oder noch besser im RunWorkerCompleted, das auch eintreffen sollte, wenn das GUI nicht blockiert ist.

herbivore

Y
yamukud Themenstarter:in
22 Beiträge seit 2009
vor 12 Jahren

Hallo herbivore,

schön wieder von dir zu lesen.

Abbrechen und neu starten ist auch keine Option, weil ich dann keinen Benefit habe.

Ich warte nicht in der GUI, sondern im Singletonobjekt.

Liebe Grüße,
yamukud

5.742 Beiträge seit 2007
vor 12 Jahren

würde ich es aus der RunWorkerCompleted-Methode heraus erlauben, die nächste Form aufzurufen, hätte ich keinen Vorteil dazu, die CSV-Datei erst bei Arbeitsbeginn zu laden.

Das war ja auch nur ein Beispiel - du sollst einfach das, was du "nach dem Warten" machen willst, in RunWorkerCompleted machen.

49.485 Beiträge seit 2005
vor 12 Jahren

Hallo yamukud,

Abbrechen und an dem Punkt, an dem abgebrochen wurde, neu zu starten, ist das beste was geht!

Und es ist auf jedenfalls besser, als alles rein sequentiell zu machen. Durch Abbrechen und Neustarten wird ja nur die Restzeit der langlaufenden Aktion "gewartet" statt die gesamt Zeit der langlaufenden Aktion wie beim rein sequentiellen Vorgehen.

herbivore