Forum: PC-Programmierung Linux-Threads - Wie am besten?


von Patrick L. (crashdemon)


Lesenswert?

Hallo Zusammen,

ich möchte auf einem Orange Pi Zero ein SW schreiben die Daten per UDP 
entgegennimmt (Helligkeitsstufen von LEDs) und diese entsprechend auf an 
die LED-Treiber weiterleitet. Jetzt dachte ich mir, dass es am besten 
wäre das Empfangen von neuen Helligkeitsstufen über UDP entkoppelt ist 
vom schreiben der Helligkeitsstufen auf dem LED-Treiber.

Dafür wollte ich Threads benutzen. Also vllt. in einem Thread das 
empfangen der Daten über UDP und in einem anderen die Ausgabe auf den 
LED-Treiber.

Macht das Sinn? Wie tauscht man die Daten am besten zwischen den Threads 
aus? FIFO-Buffer?

von g457 (Gast)


Lesenswert?

> Macht das Sinn?

Kommt auf die Rahmenbedingungen an. Kann Overkill sein, kann aber auch 
nötig sein.

> Wie tauscht man die Daten am besten zwischen den Threads aus? FIFO-Buffer?

Zum Bleistift, ja. Aber auf Fredsicherheit achten.

von ESPler (Gast)


Lesenswert?

Patrick L. schrieb:
> Jetzt dachte ich mir, dass es am besten
> wäre das Empfangen von neuen Helligkeitsstufen über UDP entkoppelt ist
> vom schreiben der Helligkeitsstufen auf dem LED-Treiber.

Warum?

Musst du neue Helligkeits-Stufen schreiben, wenn nichts per UDP gekommen 
ist?

Klar, wenn du am Netzwerk furchtbar viel Jitter hast (Wlan mit 
Auslastung am Anschlag), und trotzdem Ruckelfrei animieren willst, kann 
das Sinn machen. Aber: Es macht die Sache gleich um Größenordnungen 
komplizierter.


Beispiel in LUA auf einem NodeMCU: Per UDP (von einem Hyperion-Server) 
RGB-Daten empfangen und auf einen RGB-LED-Stripe schieben:
1
ws2812.init()
2
srv=net.createServer(net.UDP)
3
srv:listen(12345)
4
srv:on("receive", function(sck, pl) 
5
    ws2812.write(pl)
6
end)

Ohne Threads und Multitasking, auf einer CPU die vielleicht grad mal 1% 
der Performance des OrangePI bringt, in einer Scriptsprache, über 
Wlan.... Problemlos.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Patrick L. schrieb:
> Wie tauscht man die Daten am besten zwischen den Threads aus?

Des Sinn von Threads (statt verschiedenen Prozessen) ist es doch
gerade, dass sie das Datensegment des Prozesses gemeinsam nutzen
können.  Daher kannst du, wenn es schon Threads sein müssen, auch
einfache Variablen nehmen.  Vermutlich musst du dir bei dieser
Anwendung noch nicht einmal großartig Gedanken um eine Synchronisation
per Mutex oder dergleichen zu machen.

Wenn du einen FIFO nimmst, dann kannst du auch gleich getrennte
Prozesse benutzen.  Hat unter unixoiden Betriebssystemen kaum
Mehr„kosten“ im Vergleich zu Threads; läuft oft intern auf einem
gemeinsamen Interface zusammen (weiß gerade nicht, ob das bei Linux
auch so ist).

von Hannes J. (Firma: _⌨_) (pnuebergang)


Lesenswert?

Patrick L. schrieb:
> Dafür wollte ich Threads benutzen. Also vllt. in einem Thread das
> empfangen der Daten über UDP und in einem anderen die Ausgabe auf den
> LED-Treiber.
>
> Macht das Sinn?

Jein. Eigentlich sollte ein einfacher Server reichen, der nicht 
concurrent (Threads, Prozesse) arbeitet. Denn ein paar LEDs steuern 
sollte nicht so lange dauern, dass man UDP-Pakete verliert.


> Wie tauscht man die Daten am besten zwischen den Threads
> aus? FIFO-Buffer?

So in etwa. Bei zwei Threads ist das als das Producer-Consumer Problem 
bekannt. Bei mehreren Threads zur Abarbeitung als Reader-Writer Problem. 
Die Lösungen sind wohl bekannt, eigentlich sind das keine großen 
Probleme. Kannst du dir alles zusammengoogeln.

von Patrick L. (crashdemon)


Lesenswert?

Ok, danke für die Rückmeldungen. Ich höre raus, dass es wohl keinen Sinn 
macht Threads zu benutzen. Dann werde ich das nochmal überdenken.

Ich habe halt 12x TLC5940 an denen 192 LEDs hängen und ich hatte jetzt 
intuitiv gedacht, dass die Ausgabe auf allen LEDs länger dauern wird als 
das neue UDP Pakete reinkommen. Vllt. probiere ich es erstmal ohne 
Threads aus!

von Michael S. (e500)


Lesenswert?

Patrick L. schrieb:
> ... und ich hatte jetzt intuitiv gedacht, dass die Ausgabe auf allen
> LEDs länger dauern wird als das neue UDP Pakete reinkommen ...

Tja, dann hättest Du wohl ein anderes Problem oder wie würdest Du das 
dann machen wenn Du Threads hast? Nur weil Du Threads hast verlierst Du 
vielleicht keine Pakete - aber ausgeben kannst Du sie eben auch nicht 
alle also was solls, wenn Pakete verloren gehen, kannst sie auch mit 
Threads nicht bearbeiten!!

von Sven (Gast)


Lesenswert?

Sowas macht man besser mit Event Queues bzw. select oder ähnlichem. Bei 
dir wird aber auch das nicht notwendig sein, da du sonst nichts nebenher 
machen möchtest. Sockets haben einen Puffer den man konfigurieren kann, 
da werden dann keine Pakete verworfen. Wenn du das auch für den Sender 
transparent machen möchtest nimm besser TCP, das ist einfacher zu 
handhaben.

von Joachim S. (oyo)


Lesenswert?

Wie wäre es mit dem Ansatz, das Empfangen der UDP-Datenpakete einerseits 
und das Schreiben der Helligkeitsstufen auf den LED-Treiber andererseits 
in zwei komplett getrennte Programme zu platzieren, und diese beiden 
Programme dann einfach per Pipe  zu verbinden?

Also z.B. ein Programm "set_leds", das nichts weiter tut, als 
Eingabezeilen von STDIN einzulesen (z.B. als durch Kommata getrennte 
Liste von Float-Werten, die die Helligkeit beschreiben), und diese 
Helligkeitswerte dann an die LED-Treiber zu übertragen.

Und ein anderes Programm, das UDP-Pakete auf einem bestimmten Port 
empfängt und einfach 1:1 auf STDOUT ausgibt.
Wobei man dieses Programm nicht mal extra schreiben muss, dafür würde 
der Befehl genügen:
1
netcat -u -l <Port-Nummer>

Um die LEDs dann bspw. wie von Dir gewünscht per UDP-Paket an die 
Port-Nummer 50123 zu steuern, würde man folgendes Kommando eingeben 
(oder in ein eigenes Shell-Script packen):
1
netcat -u -l 50123 | set_leds
...und falls Du zu dem Schluss kommst, dass TCP doch sinnvoller als UDP 
wäre, dann änderst Du das einfach in:
1
netcat -l 50123 | set_leds
Auf diese Weise hast Du das Setzen der LEDs komplett vom UDP-Empfang 
getrennt, beides läuft in zwei unterschiedlichen Prozessen.

Und falls Du beispielsweise (z.B. zur Fehlersuche oder so) mal mitloggen 
möchtest, was empfangen wird, dann setzt Du einfach noch ein "tee" 
dazwischen, ohne irgendetwas am Programmcode ändern zu müssen:
1
netcat -u -l 50123 | tee led_log.txt | set_leds

Meiner Meinung nach wäre das der einfachste, unixoide Ansatz: getrennte 
Prozesse für UDP-Empfang und Setzen der LEDs, obwohl Du Dich gar nicht 
um Prozesse, Threads etc. kümmern musst, und den gesamten UDP-Empfang 
brauchst Du gar nicht erst zu programmieren.

von Rolf M. (rmagnus)


Lesenswert?

Jörg W. schrieb:
> Wenn du einen FIFO nimmst, dann kannst du auch gleich getrennte
> Prozesse benutzen.

Dann kann man sich einen der Prozesse aber gleich ganz sparen. Ob der 
LED-Prozess nun aus einem Socket oder einem FIFO liest, ist Jacke wie 
Hose.

von Patrick L. (crashdemon)


Lesenswert?

Michael S. schrieb:
> Tja, dann hättest Du wohl ein anderes Problem oder wie würdest Du das
> dann machen wenn Du Threads hast? Nur weil Du Threads hast verlierst Du
> vielleicht keine Pakete - aber ausgeben kannst Du sie eben auch nicht
> alle also was solls, wenn Pakete verloren gehen, kannst sie auch mit
> Threads nicht bearbeiten!!

Ja, das stimmt da hatte ich auch schon dran gedacht.. ;-)

Sven schrieb:
> Wenn du das auch für den Sender
> transparent machen möchtest nimm besser TCP, das ist einfacher zu
> handhaben.

Das geht leider nicht. Zur UDP Kommunikation nehme ich das tpm2.net 
Protokoll und die SW Jinx! Die gibt die Daten nur per UDP raus.

Joachim S. schrieb:
> Wie wäre es mit dem Ansatz, das Empfangen der UDP-Datenpakete einerseits
> und das Schreiben der Helligkeitsstufen auf den LED-Treiber andererseits
> in zwei komplett getrennte Programme zu platzieren, und diese beiden
> Programme dann einfach per Pipe  zu verbinden?

Die Idee finde ich eigenlich sehr charmant. Ich habe noch nie Programme 
geschrieben die sachen raus-pipen. Aber da kann man sich ja einlesen.

Darum einen UDP-Server zu schreiben komme ich nicht herum, weil ich ja 
das tpm2.net Protokoll interpretieren muss. Das ist aber nicht so 
schwierig. Die Implementierung habe ich schon fertig ;-)

von Joachim S. (oyo)


Lesenswert?

Patrick L. schrieb:

> Darum einen UDP-Server zu schreiben komme ich nicht herum, weil ich ja
> das tpm2.net Protokoll interpretieren muss. Das ist aber nicht so
> schwierig. Die Implementierung habe ich schon fertig ;-)

Von "tpm2.net" hatte ich bis eben noch nie gehört. Eine kurzes googlen 
machte etwas schlauer - dabei fand ich allerdings folgende Aussage:

> Das Protokoll sollte nicht auf eine spezielle HW oder Übertragungskanal
> angewiesen sein - "genormt" wird also nur, wie der Sender die Daten
> verschicken muss, so dass sie der Empfänger "versteht".

Sofern ich da nicht gerade einen Denkfehler habe, ist tpm2.net also doch 
gar nicht auf UDP beschränkt, sondern der Übertragungskanal soll ja 
vielmehr egal sein, und tpm2.net quasi nur das Datenformat definieren?
Dementsprechend wäre für mich der naheliegende Ansatz, dass das (weiter 
oben von mir beispielhaft "set_leds" genannte) Programm einen 
tmp2.net-Datenstrom als Eingabe von STDIN erwartet.
Dann wäre der Übertragungskanal wie bei tpm2.net vorgesehen völlig 
transparent, das von mir oben angesprochene pipen der Ausgabe von
"netcat -u -l 50123" für UDP als Übertragungskanal sollte genauso 
funktioneren wie z.B. eine Überträgung z.B. per UART oder das Abspielen 
einer vordefinierten Animation aus einer Datei, die tmp2.net-Daten 
enthält.

von Patrick L. (crashdemon)


Lesenswert?

Joachim S. schrieb:
> Sofern ich da nicht gerade einen Denkfehler habe, ist tpm2.net also doch
> gar nicht auf UDP beschränkt, sondern der Übertragungskanal soll ja
> vielmehr egal sein, und tpm2.net quasi nur das Datenformat definieren?

Nicht ganz. Siehe: 
http://www.ledstyles.de/index.php/Thread/18969-tpm2-Protokoll-zur-Matrix-Lichtsteuerung/

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.