Laden...

2 Threads gleichzeitig ausführen?? Windows.Forms und IO.Ports

Erstellt von darkangel1208 vor 7 Jahren Letzter Beitrag vor 7 Jahren 1.623 Views
D
darkangel1208 Themenstarter:in
20 Beiträge seit 2010
vor 7 Jahren
2 Threads gleichzeitig ausführen?? Windows.Forms und IO.Ports

Ich weiß nicht genau ob ich hier wirklich 2 Threads brauche.
Zum besseren Verständnis... ich weiß nicht wirklich wie lange die jetzt dafür brauchen....

Form1 sendet Daten über den IO-Port an ein Gerät
Dort werden die Daten verarbeitet und dann zurückgesendet.
Bei empfang von Daten des IO-Ports in der Form1, werden die Daten ausgewertet und in einer Picturebox angezeigt, bzw. in eine Textbox geschrieben

Angenommen ich sende an den IO-Port Daten und zwar 1175 mal. Das ganze würde z.B. 20 sekunden dauern.
Das externe Gerät empfängt die Daten und sendet schon nach erhalt des ersten Datensatz, also nach 3 sekunden zurück.
Aber auf der Gui wird erst nach 20 sekunden etwas in die picturebox, bzw. textbox geschrieben. Sprich 17 sekunden lang haben die Daten darauf gewartet, bis die Gui mit dem senden fertig war und sich um die empfangen Daten kümmern kann.

Problem kurz:
Form1 -> senden Daten 1
Form1 -> senden Daten 2
// etc.
Form1 -> senden Daten 1175
Form1 <- empfangene Daten1 verarbeiten
Form1 <- empfangene Daten2 verarbeiten
//etc.
Form1 <- empfangene Daten1175 verarbeiten

ich hätte aber gerne, das das senden ünterbrochen wird, sobald daten ankommen und sich darum gekümmert wird. Also eine höhere Priorität haben. Am besten so...
(Geht das nur mit threads? oder gibt es da eine kurz elegante Lösung. Denn Threads habe ich mir schon durchgelesen, aber finde ich doch schwer zu begreifen wie ich das auf mein Problem anwenden könnte.)

Form1 -> senden Daten 1
Form1 <- empfangene Daten1 verarbeiten
Form1 -> senden Daten 2
Form1 <- empfangene Daten2 verarbeiten
Form1 -> senden Daten 3
Form1 <- empfangene Daten3 verarbeiten
// etc.
Form1 -> senden Daten 1175
Form1 <- empfangene Daten1175 verarbeiten


        private void bnMouseClick_Click(object sender, EventArgs e)
        {
            uhr.Start();
            // erst wenn die schleife komplett durchgelaufen ist und bnMouseClick_Click verlassen wurde 
            // springt der Code in Empfangen rein und verarbeitet die angekommenen Daten und nicht schon sobald 
            // die Daten ankommen
            for (int i = 1; i < 1175; i++)
            {
                txtReceive.AppendText("\r\n");
                RGB = (bbc[i, 9] + "#" + bbc[i, 10] + "#" + bbc[i, 11]);
                TimeSpan zeit = uhr.Elapsed;
                double zeitneu = zeit.TotalMilliseconds;
                if ((zeitneu - zeitalt) >= 80) // erst senden, wenn 80 millisekunden seit dem letzten senden vergangen sind
                {
                      Senden(); // Senden an IO Port
                }
                else
                {
                      i=i-1;
                }
            }
            txtReceive.AppendText("\r\n ende");
            uhr.Stop();
            
        }

        private void Senden()
        {
            try
            {
                if (RGB.Length > 0)
                {

                    Arduino.Write(RGB); //senden an den IO Port
                    txtReceive.AppendText("\r\n <<<<: " + rgb[0] + "  #  " + rgb[1] + "  #  " + rgb[2]);
                    ScollToBottom();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "ERROR", MessageBoxButtons.OK);
            }
        }

        private void Empfangen(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                RGB = Arduino.ReadLine(); // empfangen vom IO port
                Berechnung_rgb_xy(); // Daten verarbeiten und in picturebox1 anzeigen
                this.Invoke(new EventHandler(Empfangen_event));
            }
            catch
            {
                MessageBox.Show("Error Serial Event Handler, cannot listen for data", "Error", MessageBoxButtons.OK);
            }
        }

        private void Empfangen_event(object sender, EventArgs e)
        {
            txtReceive.AppendText("\r\n xyz back :" + xyz[0] + "  #  " + xyz[1] + "  #  " + xyz[2]);
            txtReceive.AppendText("\r\n----------------------------------------------------------------------------------------------");
            }
            ScollToBottom();
        }

D
985 Beiträge seit 2014
vor 7 Jahren

Du brauchst das Senden nicht unterbrechen, wenn du das Senden in einem Task erledigst. Dann hat die GUI auch Zeit die ankommenden Nachrichten zu empfangen.

16.834 Beiträge seit 2008
vor 7 Jahren

Die Thread-Klasse sollte man heutzutage wirklich nur noch nutzen, wenn es unbedingt erforderlich ist.
Viel einfacher für den Entwickler sind Tasks, die im Prinzip den gleichen Effekt haben; nämlich Nebenläufigkeit.

Im Prinzip kannst Du das sehr einfach mit einer Queue abarbeiten.
Du hast SendJobs und ReceiveJobs, wobei die Queue nach ReceiveJobs sortiert/priorisiert sind, sodass diese in der Queue stets zuerst abgearbeitet werden.
Dazu gibt es auch den Priority Queue Pattern.

Der Sinn dieser Priorisierung ist mir aber nicht ersichtlich.
Warum nicht die gesamte Kommunikation in Tasks auslagern.. so würde man das eigentlich machen.

1.029 Beiträge seit 2010
vor 7 Jahren

Kann hier abt nur Recht geben. Die gescheite Vorgehensweise ist:
a) Du nutzt den ohnehin vorhandenen Task einzig für deine UI, damit die niemals hängt
b) Wenn du sendest/empfängst nutzt du je einen entsprechenden Task

Mit der Vorgehensweise brauchst du nichts zu priorisieren und alles würde flüssig durch laufen.

LG

D
darkangel1208 Themenstarter:in
20 Beiträge seit 2010
vor 7 Jahren

Problem 1:
Hmm soweit klappt das zwar jetzt. Aber alles was in meinem gestartetem Task läuft kann ja wiederrum nicht auf Textboxen der GUI zugreifen.
Wenn ich es mit this.invoke versuche, klappt das leider auch nicht.
Problem 2:
Dadurch das senden und empfangen jetzt in eigenen tasks laufen kann ich das gesendete RGBh mit dem empfangenen RGBz nicht mehr vergleichen, weil zu dem zeitpunkt, wenn ich RGBz empfange, die daten in RGBh schon evtl. wieder überschrieben wurden. (nicht immer aber manchmal)


       private void bnMouseClick_Click(object sender, EventArgs e)
        {
            Task bbcSenden = new Task(new Action(BlackBodyCurve));
            bbcSenden.Start();
        }

        private void BlackBodyCurve()
        {
            uhr.Start();
            // erst wenn die schleife komplett durchgelaufen ist und bnMouseClick_Click verlassen wurde
            // springt der Code in Empfangen rein und verarbeitet die angekommenen Daten und nicht schon sobald
            // die Daten ankommen
            for (int i = 1; i < 1175; i++)
            {
                txtReceive.AppendText("\r\n"); //Fehler
                RGBh = (bbc[i, 9] + "#" + bbc[i, 10] + "#" + bbc[i, 11]);
                TimeSpan zeit = uhr.Elapsed;
                double zeitneu = zeit.TotalMilliseconds;
                if ((zeitneu - zeitalt) >= 80) // erst senden, wenn 80 millisekunden seit dem letzten senden vergangen sind
                {
                      Senden(); // Senden an IO Port
                }
                else
                {
                      i=i-1;
                }
            }
            txtReceive.AppendText("\r\n ende"); // Fehler
            uhr.Stop();

        }

        private void Senden()
        {
            try
            {
                if (RGBh.Length > 0)
                {

                    Arduino.Write(RGBh); //senden an den IO Port
                   // txtReceive.AppendText("\r\n <<<<: " + rgb[0] + "  #  " + rgb[1] + "  #  " + rgb[2]);
                    ScollToBottom();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "ERROR", MessageBoxButtons.OK);
            }
        }

        private void Empfangen(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                RGBz = Arduino.ReadLine(); // empfangen vom IO port
                Berechnung_rgb_xy(); // Daten verarbeiten und in picturebox1 anzeigen
                this.Invoke(new EventHandler(Empfangen_event));
            }
            catch
            {
                MessageBox.Show("Error Serial Event Handler, cannot listen for data", "Error", MessageBoxButtons.OK);
            }
        }

        private void Empfangen_event(object sender, EventArgs e)
        {
            txtReceive.AppendText("\r\n xyz back :" + xyz[0] + "  #  " + xyz[1] + "  #  " + xyz[2]);
            txtReceive.AppendText("\r\n----------------------------------------------------------------------------------------------");
            }
            ScollToBottom();
        }

@Abt: ich verstehe was du meinst und ja bräuchte man eigentlich nicht, aber wie löse ich jetzt mein Problen nr. 2?

16.834 Beiträge seit 2008
vor 7 Jahren
  1. Es ist schon an Anfang des Threads wichtig, wenn Du nicht nur Nebenläufigkeit und asynchrones Verhalten, sondern auch Synchronität haben willst.
    Das wäre praktisch gewesen, das vorher zu erfahren.
  2. Probleme zu beschreiben mit "klappt nicht", hilft niemanden 😉

Ich hab ehrlich gesagt nicht so wirklich den Einblick, was Du überhaupt bauen willst.
Daher ist es auch nicht einfach, Dir zu helfen, weil offensichtlich nach und nach mehr Anforderungen hier bekannt werden.

Erzähl doch mal, was Du vor hast, bevor wir Dir jetz noch 2-3 Vorschläge bringen, die dann neue Probleme schaffen und wir unnötig Zeit investieren.
=)