Multithreading und Massnahmen zur Synchronisierung



  • Hi

    Ich muss auf arbeit Prüfabläufe in Labview schreiben. Ich meinte immer ich bekomme das schneller und eleganter in einer "richtigen" Programmiersprache hin.
    Also habe ich mich mal hingesetzt und es in C++/CLI geschrieben.
    Eine portierbare Programmiersprache wäre mir zwar lieber gewesen. Das .net ist aber sehr einfach in Labview zu intergrieren.

    Jetzt mal zum Problem. Ich habe Senden und Empfangen in zwei Threads. Das macht ja die Serialklasse schon von sich aus. Das Empfangsereigniss erzeugt einen eigenen Thread. Die Daten werden in ihre Frames aufgeteilet und in eine Liste zwischengespeichert. Auf diese Liste greifen dann verschiedene Objekte drauf zu wenn sie per Ereignis informiert wurden das die Liste einen neuen Eintrag bekommen hat.

    Diese Daten werden dann wiederum verarbeitet und in das jeweilige Objekt gespeichert. In diesen Fall ein IO-Modul mit 64 digitalen Ein/Ausgängen.

    Beim Ablauf habe ich es mir einfach machen wollen. Einen weiten Thread öffnen und da alles hineinander schreiben mit Sleeps und while-warteschleifen.

    Jetzt das Problem. Die Daten scheinen nicht sehr stabil den Prüfthread anzukommen oder davon wegzugehen. Ich habe keine direkte einfach Möglichkeit das zu debugen (besser gesagt ich kenne keine).

    Ich dachte erst an der Speicheroptimierung und habe ein paar volatile eingebaut. Doch daran liegt es auch nicht 😞 Arrays werden anscheinend eh nicht optimiert.

    In den Labview-programm welches aber Quellcodemäßig eher als hässlich zu bezeichnen ist, klappt es ganz gut.

    hoffendlich weiß einer von euch woran es liegt oder nennt ein paar Tipps und Stichpunkte zum googlen. Wenn ich irgendwas zu konfus geschrieben hab, fragt nochmal nach.

    Edit: Titel angepasst



  • 1. Du musst von verschiedenen Threads gemeinsam genutze Resourcen (z.B. deine Liste) synchronisieren. Entweder Du benutzt Locking oder marshallst alle Aufrufe auf EINEN Thread.

    2. Wenn schon .NET, dann empfehle ich dir C#. Ist einfacher von der Syntax her und hat deutlich weniger Fallstricke. Der vermeintliche Vorteil, der Interoperabilität zu nativ C++, ist wenn nicht wirklich gebraucht, ein Nachteil - besonders für Leute mit wenig Erfahrung im Bereich managed / unamanged Interoperabilität. Ausserdem ist die Syntax von C++/CLI genau so anders zu ISO C++ wie die von C# zu ISO C++.

    Simon



  • zum Locking

    wie mache ich das clever wenn ich zum beispiel in ein Objekt die Liste habe, diese lesend über eine Eigenschaft zur Verfügung stelle, aber direkt drauf schreibe aus den empfangsthread darauf schreibe?

    Ich möchte es ja alles schön übersichtlich lassen. Wenn es natürlich nötig ist dann schreibe ich was. Bloß auf globale Objekte zur Synchronisation auf eine Klasse würde ich gerne verzichten oder solche Dinge.

    Die Interoperabilität brauch ich. Außerdem komme ich mit C++ deutlich besser klar. Ich benutze C und C++ Quellcode in den Projekten aus der Firmware. Wozu nochmal schreiben wenn sie mit minimalen Anpassungen direkt funktioniert. Nur wenn das ganze dann in Labview rein soll muss man noch einen managed-Wrapper schreiben. Sonst "vergisst" Labview wichtige Dinge.



  • Falls sich die Liste selbst verändert (Add / Remove / Clear / ...) musst Du die Liste Synchronisieren.

    Falls Du eine "fixe" Liste hast und sich die Objekte darin ändern (weil beim Objekt bei Index i beschrieben wird) musst Du das jeweilige Objekt Synchronisieren.

    Hier ist die MSDN Doku dazu:
    http://msdn.microsoft.com/en-us/library/system.threading.aspx

    Die relevanten Klassen sind Mutex, Monitor, ReaderWriterLock, ReaderWriterLockSlim, Semaphore, AutoResetEvent und ManualResetEvent.

    Ich würde mal den Monitor austesten und damit versuchen zu synchronisieren.

    Simon



  • Danke das hilft mir sehr. So habe ich eine Menge zu lesen und zu lernen 🙂

    zu Monitor:
    verstehe ich das richtig?
    Wenn ich ein Abschnitt mit

    Monitor::Enter(Objekt);
    

    sicher, ist das Objekt in allen anderen bereichen wo das auch

    Monitor::Enter(Objekt);
    

    steht gesperrt? also bis irgendwann mal ein

    Monitor::Exit(Objekt);
    

    aufgerufen wird?
    kann ich so also quasi atomare Aufrufe erzeugen?



  • Ja, das hast Du korrekt verstanden.
    Und wenn Du Monitor.Enter(..) aufrufst, dieses Objekt jedoch schon vom Monitor gelockt wird, blockiert der Aufruf dort.

    Übrigens wird um Monitor.Enter(..) ... Monitor.Exit(..) ein try / finally gemacht, damit der Lock sicher wieder frei wird (auch bei einer Exception).

    Simon


Anmelden zum Antworten