Laden...

Von anderer Form auf "Main - Loop-Thread" zugreifen und stoppen

Erstellt von IncepTer vor 6 Jahren Letzter Beitrag vor 6 Jahren 1.174 Views
I
IncepTer Themenstarter:in
24 Beiträge seit 2016
vor 6 Jahren
Von anderer Form auf "Main - Loop-Thread" zugreifen und stoppen

Hallo Freunde,

*Anmerkung
mein "Problemchen" umfasst einige Themenbereiche, jedoch entschied ich mich, diesen hier zu nutzen. Sollte das Thema woanders besser aufgehoben sein, dann bitte ich um Verschiebung; danke 🙂

Kurze Zusammenfassung meines Programms und dessen Aufgabe:

Nach dem starten der Main wird mittels Backgroundworker ein neuer Thread [Name: Stunden] erstellt, wo eine Methode aufgerufen wird, die mit einer PHP Datei (lokaler Apacher) Daten aus einer MySQL DB holt und in einem Label speichern soll. Diese Methode soll regelmäßig (aller 3 Sekunden) aufgerufen werden und Daten abrufen. Sollten diese sich ändern, wird der Label-Text ergänzt. Dies haben ich so umgesetzt:

while(true) {..... 
Thread.Sleep(3000)
}
  1. Frage dazu: Ist das so empfehlenswert, oder sollte ich dies anders umsetzen?

Das funktioniert auch alles ohne Probleme. Nun möchte ich allerdings, dass der Benutzer selber einen Wert in die DB eintragen kann (über ein anderes Form) und diese soll natürlich von dem abrufenden Thread erfasst werden. Jedenfalls kann es ja zu Probleme kommen, wenn genau in dem Moment die DB von [Stunden] angezapft wird und das neue Windows-Form den Wert hineinschreibt. Dazu dachte ich mir, ich stoppe den Thread(Stunden), füge die Werte in die DB ein und Starte Thread(Stunden) wieder, bzw. starte ihn neu.

Also dachte ich mir, ich baue eine Methode zum stoppen, welche von dem neuen Windows Form aufgerufen wird:

     public void Stoppe_Datenabfrage()
        {
            if (bw.WorkerSupportsCancellation == true)
            {
                bw.CancelAsync();
            }
        }

Danach sollten dann die Werte in die DB gespeichert und der Thread neu gestartet werden.

Meine (Denk)Probleme dabei:

Ich muss ja im Worst-Case-Fall 3 Sekunden warten, bis der Thread beendet wurde, um die Daten wirklich sicher einzutragen, was natürlich schon doof sein kann. Wie kann man das am elegantesten lösen? Ich weiß auch nicht genau, inwiefern hier z.B. Table_Lock greift, wenn es nur eine sql Abfrage ist und sich somit Select und Insert eigentlich nicht stören sollten ?(

Des Weiteren besteht ja das Problem mit erstellten Element aus dem Eltern-Thread; z.b. das Label. Will ich diesen durch den Thread(Stunden) ändern, muss ich dies ja durch Invoke erledigen, oder?

  this.Invoke((MethodInvoker)delegate
   {
      lbl.Text = "WertXYZ";                         
  });

Jedoch kommt dann die Meldung:

Additional information: Invoke oder BeginInvoke kann für ein Steuerelement erst aufgerufen werden, wenn das Fensterhandle erstellt wurde.

Also kurz zusammen gefasst:

Main erstellt Thread, welcher im Loop aller 3 Sek. läuft und einen Wert aktualisiert, welcher aus einer lokalen MySQL DB geholt wird.
Der Benutzer kann durch den Button "Wert Manuell eintragen" ein neues Form (im gleichen Programm) öffnen und einen Wert in die DB einfügen. Daraufhin soll der Loop unterbrochen, der Wert ordnungsgemäß in die DB gespeichert und der Thread wieder neu gestartet werden, welcher dann wieder den/die neuen Werte holt und z.B. in einem Label speichert.

Ich hoffe Ihr wisst was ich meine und könnt ihr ein wenig den Knoten aus dem Kopf entfernen 🤔

Vielen Dank!

D
985 Beiträge seit 2014
vor 6 Jahren

Ist das so empfehlenswert, oder sollte ich dies anders umsetzen?

Setze es anders um => mit async/await und einem Timer.

Also dachte ich mir, ich baue eine Methode zum stoppen, welche von dem neuen Windows Form aufgerufen wird:

...

Danach sollten dann die Werte in die DB gespeichert und der Thread neu gestartet werden.

Nö, wieso ... wenn du den Wert direkt da hast, dann trag den in das Label ein, ansonsten frag die Datenbank eben direkt danach ab (bzw. frag den Service).

Wenn du unbedingt abbrechen (pausieren) möchtest, dann ist das mit dem Timer (s.o.) wesentlich einfacher zu lösen.

I
IncepTer Themenstarter:in
24 Beiträge seit 2016
vor 6 Jahren

Hallo Sir Rufo und besten Dank für deine Antwort 🙂

Ich habe mir deinen Rat mal gleich angenommen und etwas mit await herum-gespielt.
Prinzipiell funktioniert es so tadellos, nur habe ich da einige "Einschränkungen".
So rufe ich die Methode auf:

     privat void Starte_Datenabfrage()
        {
            Task<bool> task = Pruefe_Inhalte();
            task.ContinueWith(_ => {
                Console.WriteLine("Pruefe_Inhalte fertig:" + task.Result.ToString());
            }, TaskScheduler.FromCurrentSynchronizationContext());
        }

Und die Methode an und für sich sieht praktisch so aus:

        private async Task<bool> Pruefe_Inhalte()
        {
            bool succeeded = false;
            while (!succeeded)
            {
                  // Macht tolle Arbeit
                  await Task.Delay(2000);
            }
            return succeeded;
         }

Jetzt habe ich im Main-Form ein kleines Img, welche auftaucht, wenn z.B. an einem Tag 2 Stundenwerte eingetragen wurde. Geht man dann mit dem Mauszeiger über dieses Bild, so erscheint ein kleiner Hinweistext, der beschreibt, was da angezeigt wird.

Dieser Text wird aber nun sehr langsam und "laggend" eingeblendet; auch wenn ich das Main-Form hin und her schiebe, ist es immer etwas ... "ruckel-behaftet".

Habe ich da etwas falsch gemacht, oder wo liegt jetzt hier der Fehler? 🤔
Aber alles in allem funktioniert das so super! 👍

Beste Grüße