Multithread-Programmierung mit sehr geringen Latenzen



  • Hallo zusammen,

    ich fange gerade an, für ein komplexeres robotisches System die Regelungssoftware zu schreiben. Diese soll auf einem PC mit Echtzeit-Linux laufen.
    Jetzt habe ich das "Problem", dass an den PC mehrere Geräte angeschlossen sind, die Sensordaten und ähnliches auslesen. Jedes Gerät kommt mit einem eigenen SDK. Außerdem ist das Robotersystem an den PC angeschlossen, welches ebenfalls Sensordaten einliest und dann die Aktoren stellt.
    Das Auslesen der Sensoren soll so häufig/schnell erfolgen, wie es die Hardware erlaubt (bis zu 1 kHz) und die Aktoren sollen dann, sobald bestimmte Sensordaten vorhanden sind, neue Stellwerte erhalten, möglichst dann mit einer Latenz unter einer Millisekunde.

    Meine Idee war jetzt, dass ich für jedes Hardwareinterface einen eigenen Thread erstelle, in dem das jeweilige SDK läuft. Außerdem habe ich einen Thread, der die Regelung übernimmt. Die einzelnen Hardwareinterfaces sollen, sobald neue Sensordaten vorliegen, diese an die entsprechende Stelle in den Regelungsthread schreiben. Sobald von dem "wichtigsten" Sensor die Daten da sind, soll dieser Sensorthread dann den Regelungsthread "anstoßen", sodass neue Stellwerte berechnet werden - dies sollte genau im Millisekunden-Takt passieren.

    Welches Vorgehen kann ich da wählen? Bzw. auf welche Bibliothek sollte ich zurückgreifen? Habt ihr da Tipps?

    Also Hauptanforderungen, wie ich es gerade sehe, wäre:

    • Schreiben von Werten von einem Thread in eine Variable in einem anderen Thread (von den Sensorthreads in den Regelungsthread - das können bis zu 50 doubles pro Sensorthread sein) mit einer möglichst geringen Bearbeitungszeit/Latenz, möglichst im Bereich von 10 Mikrosekunden
    • Aufrufen einer Funktion "neuen Stellwert berechnen" von einem Thread in den anderen, wobei der aufrufende Thread dann nicht blockiert werden soll, sondern direkt im Anschluss wieder neue Sensorwerte auslesen kann.

    Würdet ihr das einfach mit std::threads aus C++11 erledigen? Oder eine weitere Bibliothek hinzuziehen? Bzw. haltet ihr das generell für ein sinnvolles Vorgehen?
    Mein erster Gedanke wäre QT mit QThreads und Signal/Slots gewesen, aber das sollte bei meinen Taktraten überfordert sein.

    Vielen Dank schon mal!



  • Welches Vorgehen kann ich da wählen?

    Die Frage ist viel zu breit. Davon abgesehen...

    Sorry wenn das jetzt nicht das ist was du hören möchtest, aber so wie du die Aufgabe und die Fragen formuliert hast, klingt das danach als ob dir viel Hintergrundwissen fehlt das wichtig wäre um das von dir beschriebene Projekt erfolgreich umzusetzen.

    Auch ist die Frage ob Realtime-Linux auf einem PC dafür am besten geeignet ist. Oder ob es nicht besser wäre hier spezielle "realtime-fähige" Hardware zu verwenden. Mit einem der für diese Hardware empfohlenen Systeme.

    Würdet ihr das einfach mit std::threads aus C++11 erledigen?

    Vermutlich nicht, da ich in so einem Projekt gerne die Möglichkeit hätte diverse Thread-Eigenschaften (wie z.B. die Priorität) selbst zu definieren. Was mit std::thread nicht geht. PTHREADS ist aber auch nicht so kompliziert - das Erzeugen der Threads wird das kleinste Problem sein.

    Oder eine weitere Bibliothek hinzuziehen?

    Ich kenne mich mit Realtime-Linux nicht aus. Könnte sein dass es da alternative Threading-Libraries gibt. Wenn ja, dann würde ich mir die mal ansehen. Ansonsten würde ich persönlich PTHREADS direkt verwenden.

    Bzw. haltet ihr das generell für ein sinnvolles Vorgehen?

    Schwer zu sagen. Dazu müsste man die Vorgaben viel genauer kennen. Und selbst wenn man sie kennt, ich denke hier wäre Prototyping angesagt. Also eine Quick & Dirty Implementierung mit einem Test-System machen und dann gucken wie gut es läuft. Wenns nicht gut läuft gucken wieso und was man machen kann. Was dann möglicherweise auch sein kann: auf ein anderes System (Hardware, OS) umsteigen.

    Mein erster Gedanke wäre QT mit QThreads und Signal/Slots gewesen, aber das sollte bei meinen Taktraten überfordert sein.

    Mit QThreads erzeugst du bloss die Threads, wenn die mal laufen ist da kein Unterschied mehr. Also abgesehen davon dass man vermutlich weniger Kontrolle über das Erzeugen der Threads hat als wenn man es selbst macht. Und was Signals/Slots angeht: wenn du genau das brauchst was Qt Signals/Slots anbieten, dann wird der Overhead den die Qt Signals/Slots Implementierung hat vermutlich kein Problem sein. Wobei ich ehrlich gesagt nicht wüsste wo man hier Signals/Slots verwenden würde/könnte.



  • @hustbaer sagte in Multithread-Programmierung mit sehr geringen Latenzen:

    Wobei ich ehrlich gesagt nicht wüsste wo man hier Signals/Slots verwenden würde/könnte.

    Wahrscheinlich, um den Controller-Thread zu benachrichtigen, dass neue Sensordaten vorliegen...
    Von Qt an sich halte ich jetzt nicht sooo viel. Wir benutzen das in der Arbeit. Meist ist es für viele Aufgaben gut genug und angenehm. Aber es ist praktisch nie die beste oder performanteste Lösung. Abgesehen von GUI vielleicht. Alles andere kriegst du auch ohne Qt besser hin, wenn du dich etwas auskennst.

    Ich bin kein Experte für Echtzeitsysteme, aber irgendwie hört sich der Ansatz für mich etwas widersprüchlich an. Der Sinn von RT Linux ist, den Einfluß des Kernels zu minimieren, damit man harte Echtzeitanforderungen besser unter Kontrolle hat. Also, hauptsächlich, damit nicht plötzlich irgendwas anderes reinfunkt. Das machst du aber wieder komplett zunichte, indem du mehrere Echtzeitsysteme auf dem gleichen System laufen lässt. Ich wäre da ehrlich gesagt sehr skeptisch.



  • @Mechanics sagte in Multithread-Programmierung mit sehr geringen Latenzen:

    @hustbaer sagte in Multithread-Programmierung mit sehr geringen Latenzen:

    Wobei ich ehrlich gesagt nicht wüsste wo man hier Signals/Slots verwenden würde/könnte.

    Wahrscheinlich, um den Controller-Thread zu benachrichtigen, dass neue Sensordaten vorliegen...

    Möglich. Wobei das etwas ist was man IMO genau so gut fest verdrahten kann. Und vor allem: Dass man die Funktion "in einem anderen Thread aufrufen" möchte und der aufrufende Thread sofort weiterlaufen soll, dabei hilft Signals/Slots auch nicht. Dafür braucht man etwas wie Condition-Variablen.

    Und ich habe stark den Eindruck dass der OP meint er könnte genau diesen "in einem anderen Thread aufrufen" Teil damit hinbekommen.



  • Wobei 10 usec auch nicht unschaffbar klingt mit der üblichen "Thread+Queue"-Mechanik. Man braucht halt nur ne lock-free-Queue und ein paar Threads die sich keine Pausen gönnen 😉 Je nachdem wie teuer die "Bearbeitung" ist, könnte man die Daten auch parallel verarbeiten, müsste die dann aber hinten raus wieder synchronisieren, da die Reihenfolge der Messdaten vermutlich erhalten bleiben soll.

    Klingt nach einer coolen Aufgabe für den nächsten kleinen Programmierwettbewerb meines Teams 😉



  • @Manuelito Bzw. haltet ihr das generell für ein sinnvolles Vorgehen?

    Mein erster Gedanke wäre QT mit QThreads und Signal/Slots gewesen, aber das sollte bei meinen Taktraten überfordert sein.

    Generell halte ich die Herangehensweise für überdenkenswert. Besonders, wenn ich was von Doubles höre, wobei das heutzutage machbar sein könnte, aber auch RT- Subsysteme haben ihre Grenzen. Daß was ins Holpern gerät, erlauben mir meine Chefs nicht.
    Was ist heute der Sysloop- Zyklus? Immer noch so um die 4 ms?

    Also, bevorzugt sammle ich Sensor/Aktor- Ergebnispakete auf µCs, die per USB oder SPI abgerufen werden (können), das kann man auf DMA- Kanäle schieben und das OS bei der Systemsteuerung darüber ist dann fast egal.

    Very Old Fashioned, funzt aber.



  • @Sarkast sagte in Multithread-Programmierung mit sehr geringen Latenzen:

    Also, bevorzugt sammle ich Sensor/Aktor- Ergebnispakete auf µCs, die per USB oder SPI abgerufen werden (können), das kann man auf DMA- Kanäle schieben und das OS bei der Systemsteuerung darüber ist dann fast egal.

    Genau das ist auch mein Gedanke.

    Bei Zykluszeiten von 1ms und Zugriffszeiten von 100us denke ich eher an Bare Machine Software, Interrupts und DMA als an QT und Threads. Ich habe da etwas Angst dass das OS/QT mir einige Verzögerungen durch Thread Synchronisation, Context Switches oder sonstigen Klimbims verursacht. Aber ich habe diesbezüglich keine Erfahrung mit Echtzeit-Betriebssystemen.

    Ist aber auch eine Frage wie hart die Echtzeit-Anforderungen sind.



  • @Quiche-Lorraine Manchmal so hart, daß man auf Assembler- Ebene alle NMIs sperren oder wenigstens sofort returnen muß. Es ist oft schwer, beim Design zu erklären, wann was wohin muß.
    In Zehnerpotenzen würde ich einem aktuellen PC bei allen OS die Bedienung von Anforderungen aufs kHZ zutrauen, wenn man an der Sysloop vorbeikommt, aber nicht mehr.
    Ich tu' grad mit nem RasPi rum, is geil, knickt aber genauso ein, wie mein oller 386er.



  • Dieser Beitrag wurde gelöscht!


  • Dieser Beitrag wurde gelöscht!


  • Dieser Beitrag wurde gelöscht!