Synchronisation von Listen bei Zugriffen durch mehrere Prozesse

Tharsonius

Bekanntes Mitglied
Hallo zusammen,

ich arbeite aktuell an einem Programm, welches die serielle Schnittstelle nutzt. Soweit so gut, RXTX funktioniert auch.
Nun kommt aber dazu, dass ich mehrere Threads habe.

Prozess 1 schreibt auf die serielle Schnittstelle,
Prozess 2 liest azf der seriellen Schnittstelle und
Prozess 3 ist das Programm selber, welches auch die Daten verarbeitet.

Dazu habe ich 2 Listen generiert, die als Puffer fungieren. Beide befinden sich in Prozess 3. Dazu gibt es entsprechende Methoden, um auf besagte Listen zugreifen. Das ganze sieht dann so aus:


Prozess 1 - gekürzt
Java:
final class SerialWriter
extends Thread
{
  private OutputStream stream;
  private Serial serial;
  private boolean run;
  
  protected SerialWriter(Serial serial, OutputStream stream)
  {
    this.stream = stream;
    this.serial = serial;
    run = true;
  }
  
  protected final void exit()  // Hierüber wird von Prozess 3 aus dieser Prozess beendet
  {
    run = false;
  }
  
  public final void run ()
  {
    Nachricht message;
    while(run == true)
    {
      message = serial.getSendMessage();  // Hier wird die Nachricht aus Prozess 3 geholt.
      if(message == null)
      {
        try
        {
          sleep(200);
        }
        catch(InterruptedException e)
        {
          //Nix tun
        }
      }
      else
      {
        try
        {
          stream.write(message.getID());
          
          [...]
          
        }
        catch(IOException e)
        {
          serial.sendefehler();   // Hier wird ein eventueller Fehler an Prozess weiter gereicht
        }
      }
    }
  }
}


Prozess 2 - gekürzt
Java:
final class SerialReader
extends Thread
{
  private InputStream stream;
  private Serial serial;
  private boolean run;
  
  protected SerialReader(Serial serial, InputStream stream)
  {
    this.stream = stream;
    this.serial = serial;
    run = true;
  }
  
  protected final void exit()  // Hierüber wird von Prozess 3 aus dieser Prozess beendet
  {
    run = false;
  }
  
  public final void run ()
  {
    int wert;
    boolean gewartet;
    while(run == true)
    {
      gewartet = false;
      try
      {
        wert = stream.read();
      }
      catch(IOException e)
      {
        serial.empfangfehler();
        wert = -1;
      }
      if(wert == -1)
      {
        try
        {
          sleep(100);
        }
        catch(InterruptedException e)
        {
          //Nix tun
        }
      }
      else
      {
        EmpfangsNachricht message = new EmpfangsNachricht();
        try
        {
          message.setzeID(wert);
          wert = stream.read();
          if(wert == -1 && gewartet == false)
          {
            try
            {
              sleep(100);
            }
            catch(InterruptedException e)
            {
              //Nix tun
            }
            gewartet = true;
            wert = stream.read();
          }
          if(wert == -1)
          {
            message.setzeStatus(false);
            serial.setReceiveMessage(message);
            continue;
          }
          message.setzeDLC(wert);
          
          [...]
          
          
          serial.setReceiveMessage(message);  // Hier wird die nachricht an Prozess 3 weiter gereicht
        }
        catch(IOException e)
        {
          serial.empfangfehler();     // Hier wird ein eventueller Fehler an Prozess weiter gereicht
        }
      }
    }
  }
}


Prozess 3 - relevante Teile
Java:
public final class Serial
{
  private LinkedList<Nachricht> sendepuffer;
  private LinkedList<EmpfangsNachricht> empfangspuffer;
  private SerialReader reader;
  private SerialWriter writer;

  public Serial()
  {
    sendepuffer = new LinkedList<Nachricht>();
    empfangspuffer = new LinkedList<EmpfangsNachricht>();
  }

  public final boolean open(String port, int baud)
  {
    [ ... ]

    InputStream in;
    OutputStream out;
    try
    {
      in = serialPort.getInputStream();
      out = serialPort.getOutputStream();
    }
    catch(IOException e)
    {
      serialPort.close();
      return false;
    }
    reader = new SerialReader(this, in);
    reader.start();
    writer = new SerialWriter (this, out);
    writer.start();
    geoeffnet = true;
    return true;
  }

  public synchronized final boolean close()
  {
    if(geoeffnet == false)
      return true;
    reader.exit();
    writer.exit();
    serialPort.close();
    geoeffnet = false;
    return true;
  }

  public synchronized final boolean transmit(Nachricht message)
  {
    sendepuffer.add(message);
    return true;
  }
  
  public synchronized final EmpfangsNachricht receive()
  {
    EmpfangsNachricht message = empfangspuffer.remove();
    return message;
  }
  
  protected synchronized final Nachricht getSendMessage()
  {
    Nachricht message = sendepuffer.remove();
    return message;
  }
  
  protected synchronized final void setReceiveMessage(EmpfangsNachricht message)
  {
    empfangspuffer.add(message);
  }
  
  protected synchronized final void empfangfehler()
  {
    fehler = true;
  }
  
  protected synchronized final void sendefehler()
  {
    fehler = true;
  }
}


Meine Frage ist nun, habe ich dies mit dem synchronized bei den Methoden richtig gemacht?
Muss ich die Methoden synchronisieren oder muss ich das ganze eventuell ganz anders machen.
Ich muss zugeben, so 100% blicke ich das noch nicht.

Was ich halt verhindern will ist, dass eine Nachricht eventuell nur halb in einen ansonsten leeren Puffer geschoben wird und dann eine Auswertung erfolg und alles irgendwie vor die Wand läuft.

Also habe ich mir gedacht, in Prozess 3 muss ich die Zugriffsmethoden auf die Liste, egal von welcher Seite synchronisieren, oder?


Außerdem möchte ich natürlich die Prozesse 1 und 2 sauber beenden, wenn die Serielle Schnittstelle nicht mehr benötigt wird. Ob nach beenden Aufforderung bis zum wirklichen beenden noch etwas in den Puffer geschrieben wird ist dabei egal, da dies nicht mehr verarbeitet wird und etwas später sowieso verworfen wird.

Ich hoffe Ihr könnt mir sagen, ob das so passt oder eher vollkommener Blödsinn ist.
 

Michael...

Top Contributor
Bin jetzt nicht so wirklich aus dem Code schlau geworden, was Du vorhast.

Auf die Listen sende- und empfangspuffer ist der Zugriff nur synchronized möglich, das war ja das was Du wolltest !? Könntest Dir auch mal ConcurrentLinkedQueue anschauen.

Allerdings wird (soweit ich das richtig überblickt habe) nur von jeweils einem Thread auf eine Liste zugeriffen, daher ist das synchronized eigentlich nicht notwendig. Und es stellt sich die Frage was erhoffst Du damit zu erreichen?

Genauso bei
Code:
synchronized final void empfangfehler()
und
Code:
synchronized final void sendefehler()
beide mal setzt Du fehler auf true und ich sehe auch nirgends, dass fehler zurückgesetzt wird. Das ist jetzt nicht unbedingt verkehrt, aber auch nicht notwendig, daher auch hier die Frage warum?

Ansonsten: Für
Code:
while(run == true)
kann man auch einfach
Code:
while(run)
und für
Code:
if(geoeffnet == false)
einfach
Code:
if(!geoeffnet)
schreiben- ist aber auch ein bisschen Geschmacksache.

Dann noch dieses sleep(...) an mehreren Stellen. Kann es sein, dass Du bei leerer Liste damit warten willst um dann erneut zu überprüfen, ob was in der Liste drin steht? Wenn ja, dann informiere den Thread einfach wenn es in der Liste was zu lesen gibt bzw. wenn sich der Inhalt der Liste verändert.
 

Tharsonius

Bekanntes Mitglied
Na ja, zu dem was ich machen will, ich will Daten über die serielle Schnittstelle versenden und empfangen. An der Gegenseite wird sich ein Microcontroller mit entsprechender Schaltung befinden, der sporadisch Daten sendet, die ich dann empfangen und verarbeiten muss. Auch muss ich selber einige Einstellungsdaten an den Controller senden. Aber das ist grundlegend erst mal egal, mir geht es nur darum ob ich das mit der synchronisation so richtig verstanden habe.


Der SerialWriter greift auf den sendepuffer zu, der SerialReader auf den Empfangspuffer. Beide laufen als separate Threads.
Die Klasse Serial wiederum ist in einem ganz anderen Thread untergebracht, meinem eigentlichen Programm.

Dieses Programm wiederum hat eigene Methoden receive und transmit, um jeweils auf die Puffer zuzugreifen.

Mir geht es derzeit nur darum, ob ich das mit der synchronisation so richtig habe, dass man die Methoden synchronisiert oder ob man das halt doch etwas anders machen muss.



Was den Fehler angeht, der wird durchaus noch ausgelesen und kann auch zurück gesetzt werden, diese beiden Methoden habe ich aber noch nicht. Das zurücksetzen würde ich auch als synchronisierte Methode schreiben. Dieser Bereich ist noch nicht 100%ig fertig ;-)



Der Gedanke zu dem Sleep ist, dass ich, solange nix zu senden ist einfach warte und wenn gerade nix empfangen wurde, dann ebenfalls warte. Aber bei leerer Liste zu informieren ist eine Idee, zumindest was das senden angeht. Empfangsseitig wird das nicht gehen. Muss mir das mal raussuchen, wie ich das entsprechend ändern kann.
 

FArt

Top Contributor
Du hast ein typisches Producer/Consumer Problem. Google mal danach und mache es wie vorgeschlagen. sleep und aktives Polling ist nicht der Bringer.
Dringender Vorschlag: das java.util.concurrency Package und eine Queue.
 

Tharsonius

Bekanntes Mitglied
So gesehen habe ich das ganze also 2 mal:
Einmal ist mein Hauptprogramm der Producer und der SerialWriter der Consumer, und zum anderen ist mein SerialReader ein anderer Producer wärend mein Hauptprogramm hier der Consumer ist.

Nur mit der Abwandlung, dass das Objekt, was die Listen verwaltet bei mir ebenfalls im Hauptprogramm läuft.
In den Beispielen sind Producer und Consumer immer separate Threads und das Listenobjekt liegt im Hauptprogramm. Das ist bei mir anders, hier muss ich mal schauen wie das umsetzbar ist.


Bezüglich Queue, da habe ich Listen genommen, gehen die nicht?
Alles in allem werden die Anzahl der Daten überschaubar sein, es darf keine Nachricht verloren gehen, die Queue darf sozusagen niemals voll werden. Zu sendende Nachrichten werden nur wenige produziert und empfangene Nachrichten werden praktisch sofort verarbeitet.
 
Zuletzt bearbeitet:

Michael...

Top Contributor
Mir geht es derzeit nur darum, ob ich das mit der synchronisation so richtig habe, dass man die Methoden synchronisiert oder ob man das halt doch etwas anders machen muss.
Da bin ich mir nicht so ganz sicher. Mit den synchronized Methoden erreicht man, dass solange die Methode abgearbeitet wird nur ein Thread diese und weitere synchronzied Methoden auf diesem Objekt aufrufen kann, alle anderen Threads müssen warten.
D.h. da in der Klasse Serial so ziemlich alle Methoden synchronized sind, kann solange z.B. der SerialReader die
Code:
setReceiveMessage(message);
abarbeitet, der SerialWriter kein getSendMessage() oder sendefehler() aufrufen - und das ist glaube ich nicht deine Absicht. Der Reader soll doch sicherlich den Empfangspuffer bearbeiten können, auch wenn der Writer gerade was aus dem Sendepuffer ausliest.
 

Tharsonius

Bekanntes Mitglied
Das heißt ich müsste die Puffer entsprechend auslagern und daraus separate Objekte machen. Serial wird dann auf die Puffer zugreifen, je nachdem was es ist wird dann der entsprechende Puffer angesteuert und kann ich beides parallel machen?

Ich glaube so laaaangsam, aber wirklich nur langsam lichtet sich etwas der Nebel ;-)
Ich muss da glaub ich erst mal noch etwas mehr lesen...
 
G

Gast2

Gast
Moin,

Du brauchst nur 2 Threads ... Lesen und Schreiben sind untereinander atomar ... so wie Du Dein Byte-Array an das BS übergeben hast liegt es am BS ... selbst die Hardware kümmert sich schon darum das auf der Leitung nichts kollidiert

der eine Thread kümmert sich nur um das einlesen ... dabei ist ein lokes Byte-Array von Vorteil ... immerhin hast Du einen Sequence-Anfang (0xff) - persönlich halte ich aber Dein Sequence-Ende (0xff) für ungünstig ... ich bevorzuge hier einen Sequence-Anfang und im nächsten Byte eine entsprechende Längenangabe ... wenn Dein Paket immer X Bytes ist, kannst Du Dir die Längenangabe sparen

Code:
public byte [] serialRead()
{
  int position = 0;
  byte [] message = new byte [5]; // bei fester länge, sonst init nachdem Länge steht
  while(true)
  {
    int b = 0xff & serial.read();
    if (b == 0xff) position = 0; // Reset
    message[position++] = b; // Index testen !!
    if (position > message.length) break; // Paket erhalten
  }
  return message;
}

allerdings musst Du selber entscheiden wie lange die Verarbeitung des Paket dauert ... bei mir hat es bisher immer ausgereicht, die Daten im selben Thread zu verarbeiten ... ansonsten in eine Queue packen ... dafür entsprechend beiden Methoden mit synchronized absichern ... und über einen bzw. andere Threads abarbeiten -> Consumer/Producer-Problem (wurde aber schon genannt)

hand, mogel
 

Tharsonius

Bekanntes Mitglied
@Michael... : Werde ich mir mal anschauen.

@mogel: Wieso Sequenz Anfang / Ende? Wieso 0xff? Davon habe ich nie was geschrieben. Meine Nachricht besteht aus ID, Datenlängenfeld, 0-8 Daten und CRC, dabei kann jeder Wert 0x00-0xff sein.
Aber davon hatte ich bewusst nix geschrieben.
 
G

Gast2

Gast
dann misintepretierte ich Dinge wie

Java:
if(wert == -1)

zumindest hast Du ein Protokoll - was die meisten vergessen vorher zudefinieren
 

Tharsonius

Bekanntes Mitglied
Ich hab das ganze jetzt gelöst, danke an alle für die Tips.

Ich habe zwei Puffer Objekte erstellt, einmal für Empfang, einmal für senden.

In meinem Hauptprogramm erstelle ich nun die beiden Puffer und übergebe diese an meine SerialReader und Serial Writer, sie als separate Threads laufen.

Zugriff auf den Puffer ist jeweils über synchronized(puffer) {}

Auch habe ich das polling durch ein wait() / notify() abgesichert, soweit möglich.
 

FArt

Top Contributor
Ich hab das ganze jetzt gelöst, danke an alle für die Tips.

Ich habe zwei Puffer Objekte erstellt, einmal für Empfang, einmal für senden.

In meinem Hauptprogramm erstelle ich nun die beiden Puffer und übergebe diese an meine SerialReader und Serial Writer, sie als separate Threads laufen.

Zugriff auf den Puffer ist jeweils über synchronized(puffer) {}

Auch habe ich das polling durch ein wait() / notify() abgesichert, soweit möglich.

Sieht nach einer sinnvollen Lösung aus. Sieht auch so aus, als hättest du verstandes was du da machst.. die Frage davor sah noch nicht so aus ;-)
 

Tharsonius

Bekanntes Mitglied
Sieht nach einer sinnvollen Lösung aus. Sieht auch so aus, als hättest du verstandes was du da machst.. die Frage davor sah noch nicht so aus ;-)

na ja, obs Sinnvoll ist werde ich sehen. Ja, das erste war... ein erster Versuch...
Ich hatte keinen Peil und hab mir das so in etwa gedacht und deshalb mal nachgefragt. Na ja, hab das erste mal mit mehreren Prozessen zu tun.. Aber hey, man lernt ja ;-)

Nochmals Danke für den Anstoß in die richtige Richtung.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
T Synchronisation einer Textdatei im Groupshare Allgemeine Java-Themen 1
G Synchronisation nicht statischer Methoden Allgemeine Java-Themen 4
R Threads korrekte Synchronisation bei Vector und ArrayList Allgemeine Java-Themen 6
K Threads - Swing - Synchronisation nötig? Allgemeine Java-Themen 8
K Thread Synchronisation Allgemeine Java-Themen 8
F Bluetooth / Synchronisation : Problem mit einer Bluetoothanwendung Allgemeine Java-Themen 3
T Project Synchronisation Allgemeine Java-Themen 4
B Ausgabe auf der Konsole bei Nebenläufigkeit, Threads und Synchronisation Allgemeine Java-Themen 8
B Nebenläufigkeit, Threads und Synchronisation Allgemeine Java-Themen 10
R Konzept eines Software-Rollout/Synchronisation via WebService Allgemeine Java-Themen 5
H Thread Synchronisation. mutex.lock(); und mutex.unlock(); Allgemeine Java-Themen 4
S Synchronisation von Threads Allgemeine Java-Themen 7
T problem mit synchronisation Allgemeine Java-Themen 4
G Links zum Thema Synchronisation Allgemeine Java-Themen 7
H LRUMap und Synchronisation Allgemeine Java-Themen 5
F Synchronisation + Vector/ArrayList/LinkedList Allgemeine Java-Themen 7
S synchronisation einer Methode abhängig vom Parameter Allgemeine Java-Themen 10
S Threads und Synchronisation Allgemeine Java-Themen 3
A Synchronisation Datenquelle und Anwendung (Multi-User) Allgemeine Java-Themen 7
A Daten-Synchronisation Client <-> Datenquelle (DB) ? Allgemeine Java-Themen 6
C Synchronisation aber trotzdem parallel lesen Allgemeine Java-Themen 2
D Zwei Listen vergleichen Allgemeine Java-Themen 7
M doppelt verkettete Listen Allgemeine Java-Themen 2
L Listen Allgemeine Java-Themen 3
F Verständnisprobleme Aufgabenstellung Aktionsobjekte und generische Listen Allgemeine Java-Themen 1
E Listen in Java aneinanderfügen, subtrahieeren usw. Allgemeine Java-Themen 14
C Fehler beim Debuggen von Listen Allgemeine Java-Themen 4
J Mit Referenzen verkettet Listen. Allgemeine Java-Themen 9
S Intressante Benchmark-Ergebnisse mit Listen. Weiss jemand wie man diese erklaeren kann? Allgemeine Java-Themen 15
D Best Practice Die niedrigste Differenz zwischen zwei Listen ermitteln. Allgemeine Java-Themen 10
F Listen - Mehrere Objekte Allgemeine Java-Themen 1
P Listen sortieren Allgemeine Java-Themen 1
RalleYTN Collections Verständnisfrage zu Objektreferenzen in Listen Allgemeine Java-Themen 5
C Listen Allgemeine Java-Themen 1
M liste von listen anders ausgeben Allgemeine Java-Themen 1
W Sortierte Listen - Methode suchen Allgemeine Java-Themen 17
W Sortierte Listen mit Polymorphismus Allgemeine Java-Themen 6
J Rekursion oder Iteration - verkettete Listen Allgemeine Java-Themen 8
S Permutation und Listen Allgemeine Java-Themen 2
P Doppeltverkettete Listen + Text Allgemeine Java-Themen 5
A Java Projekt (Daten Eingeben, Speichern und in Listen Ausgeben) Allgemeine Java-Themen 6
F JAXB / Listen durchlaufen Allgemeine Java-Themen 17
T Drucken von variabel langen Listen (es kommen nur leere Seiten raus) Allgemeine Java-Themen 2
F Vergleich zweier Listen Allgemeine Java-Themen 4
D variabler Listen name Allgemeine Java-Themen 3
V Drucken von Listen Allgemeine Java-Themen 6
S Doppelte Werte in Listen,Vectoren etc suchen Allgemeine Java-Themen 2
L verkettete Listen oder Arrays + Indexlisten effizienter? Allgemeine Java-Themen 3
M Addieren von Listen Allgemeine Java-Themen 2
F Objekte oder besser ID in Listen speichern? Allgemeine Java-Themen 2
S Mehrere Listen ineinander verschachteln Allgemeine Java-Themen 22
S Alle Elemente von zwei Listen vergleichen Allgemeine Java-Themen 10
R Objektsynchronisierung zweier Listen?!?! Allgemeine Java-Themen 2
H Listen Allgemeine Java-Themen 5
G Datenstruktur: LISTEN Allgemeine Java-Themen 7
J Verschachtelte ListIteratoren um in zwei Listen hin und herzugehen Allgemeine Java-Themen 5
C Problem Methoden, Klassen, Listen Allgemeine Java-Themen 27
K Listen,Bäume,Mengen Allgemeine Java-Themen 3
S Hinzufügen von Elementen zu Listen Allgemeine Java-Themen 4
A zwei listen vergleichen und unterschiede anzeigen Allgemeine Java-Themen 3
D Listen / Datenstrukturen und ein blutiger Anfänger Allgemeine Java-Themen 7
J Zwei sortierte Listen zusammenfassen Allgemeine Java-Themen 8
T Problem mit Listen Allgemeine Java-Themen 8
B binarysearch bei listen mit klassen Allgemeine Java-Themen 4
F Problem mit Java Listen Allgemeine Java-Themen 4
D Listen von Generischen Typen inkl. Vererbung Allgemeine Java-Themen 2
C Listen in Java. Anehängter Code nicht ganz klar Allgemeine Java-Themen 19
L Doppelt Verkettete Listen Allgemeine Java-Themen 6
E Verkettete Listen Allgemeine Java-Themen 5
M objekt mit listen Allgemeine Java-Themen 5
G Domainen crawlen & Domainnamen listen -> LANGSAM! Allgemeine Java-Themen 19
M Listen Problem! Allgemeine Java-Themen 26
M doppelt verkettete Listen? Allgemeine Java-Themen 5
M Serialisierte listen ausgeben? Allgemeine Java-Themen 6
F 2 Varianten für synchronisierten Zugriff auf Listen Allgemeine Java-Themen 2
L Welche Collection ist die richtige ? Listen mergen Allgemeine Java-Themen 3
G Synchronisierte Listen. ein Graus Allgemeine Java-Themen 4
M Verknüpfung von Listen Allgemeine Java-Themen 3
S Frage zu ArrayList mit Listen Allgemeine Java-Themen 8
S Fragen zu 4 speziellen Listen Allgemeine Java-Themen 4
D Listen Allgemeine Java-Themen 4
M sortierte listen Allgemeine Java-Themen 5
I Doppelt verkette Listen Allgemeine Java-Themen 2
B Input/Output Schneller Sort mit wenigen Zugriffen (oder was anderes?) Allgemeine Java-Themen 3
M Implementation von Zugriffen auf Object[index] in der JVM Allgemeine Java-Themen 9

Ähnliche Java Themen

Neue Themen


Oben