Forum: PC-Programmierung Datenübergabe an GUI-Thread


von C# Beginner (Gast)


Lesenswert?

Hallo,
ich habe einen Thread, der Daten von der seriellen Schnittstelle 
einliest.
Diese sollen auf der Console ausgegeben werden.
Die Ausgabe soll im eigenen Thread stattfinden, um den Einlsese-Thread 
nicht zu blockieren.
Dieser Ansatz funktioniert nicht ganz so toll:
1
    while (_continue)
2
    {
3
      try
4
      {
5
        if (_serialPort.BytesToRead > 0) {
6
          var ret = _serialPort.Read(arr,0,_serialPort.BytesToRead);
7
          if (ret > 0) {
8
            this.BeginInvoke((MethodInvoker) delegate {
9
              for (int i=0;i<ret;i++) {
10
                Console.WriteLine("{0,5}:{1,2:X}",cnt,arr[i]);
11
                cnt++;
12
              }
13
            });
14
          }
15
        }
16
      }
17
      catch (TimeoutException) { }
18
    }


Das Problem ist, wenn die Ausgabe-Routine verzögert ist, dann gibt der 
WriteLine nicht die Werte (arr[]) aus, mit der das delegate aufgerufen 
wurde, sondern die bereits aktualisierten.
D.h. werden die Werte 1,2,3,4,5 empfangen, so gibt er z.B. 1,2,4,4,5 
aus.
Ich hatte schon arr[] zwischengespeichert, damit die ursprünglichen 
Werte für das delegate erhalten blieben, aber das funktioniert auch 
nicht.
Was tun?

von Manfred M. (bittbeisser)


Lesenswert?

Mit C# kenne ich mich nicht aus. Aber sobald du mit mehreren Threads 
arbeitest, musst du dich auch mit IPC (inter process communication) und 
Mutexe befassen.

Was du da vor hast ist eigentlich ein typischer Anwendungsfall für einen 
Ringpuffer oder ein FIFO, auf den immer nur ein Thread zur Zeit 
zugreifen darf.

Trivial ist des jedenfalls nicht.

von nicht"Gast" (Gast)


Lesenswert?

Moin,

tja, das Leid mit den Threads^^

Der Weg, den du gehst ist übrigens ungewöhnlich. Die Klasse SerialPort 
kann bereits asyncron lesen. Da brauchst du keinen eigenen Thread für 
aufmachen.
1
SerialPort myPort;
2
3
void init()
4
{
5
    myPort = new SerialPort("com1");
6
    myPort.DataReceived += dataReveived;
7
    myPort.Open()
8
9
}
10
11
12
StringBuilder dataStorage = new StringBuilder();
13
Object lockObject = new Object();
14
void dataRecevied(Object sender, SerialDataReceivedEventArgs e)
15
{
16
    // wird aufgerufen, wenn Daten am Port eintrudeln.
17
    
18
    lock(lockObject)
19
    {
20
        var readData = myPort.ReadExisting();
21
        dataStorage.Append(readData);
22
        printNewData(readData);    
23
    }
24
}

Ich hab das ganze natürlich vereinfacht dargestellt.

Das hat für dich vor allem den Vorteil, dass beim Eintrudeln von Daten 
ein neuer Aufruf der Methode erfolgt. Will sagen, die lokalen Variablen 
werden nicht Überschrieben. Egal, ob die ausgegeben werden oder nicht.

Ich weiß grad gar nicht, was ich noch schreiben soll. Na ja, wenn du 
Fragen hast, dann raus damit :)

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.