Hallo an alle, Ich habe eine Frage zu Threads. Und zwar ich habe zwei Threads: THREAD_A und THREAD_B. In beiden Threads soll auf die serielle Schnittstelle geschrieben werden. Mir ist klar, dass ich vor einem Zugriff auf die Schnittstelle (zB fprintf) den kritischen Bereich mit einem Mutex sperren muss. Nun zu meiner eigenen Frage, ich kann ja einen Stream, eben /dev/tts/0, mehrfach öffnen. Ich musss nur verhindern, dass nicht gleichzeitig zugegeriffen wird(eben mit dem Mutex). Ist es besser so, oder einen gloabel Filedeskriptor für den Stream?? Danke im Voraus mfg Stefan
Stefan schrieb: > Nun zu meiner eigenen Frage, ich kann ja einen Stream, eben /dev/tts/0, > mehrfach öffnen. Ich musss nur verhindern, dass nicht gleichzeitig > zugegeriffen wird(eben mit dem Mutex). > > Ist es besser so, oder einen gloabel Filedeskriptor für den Stream?? Hm, ohne genau zu wissen was Du da machst ist es schwierig, diese Frage zu beantworten. Tendenziell würde ich sagen: Ein globales Filehandle könnte besser sein. Allerdings frage ich mich, warum Du mit zwei Threads auf die serielle Schnittstelle zugreifst. Wenn ich mich recht entsinne wars der Kernel-Guru Alan Cox, der mal geäußert hat, dass Threads was für Leute sind, die keine State Machines (sauber) implementieren können. Und damit hat er möglicherweise auch garnicht so unrecht :-) Stephan
Stephan M. schrieb: > Wenn ich mich recht entsinne wars der > Kernel-Guru Alan Cox, der mal geäußert hat, dass Threads was für Leute > sind, die keine State Machines (sauber) implementieren können. Und damit > hat er möglicherweise auch garnicht so unrecht :-) Alte Ausrede fuer Leute, die mit Threads nicht umgehen koennen... leider die Mehrheit und die hat ja immer recht :-/
Hallo, Nun ich denke genau Threads sind für mein Problem die Lösung. Und zwar im THREAD_A scanne ich alle 5 Sekunden scanne ich einen Ordner und bei einer Änderung sende ich etwas über die serielle Schnittstelle. Der THREAD_B liest zyklisch etwas auf der seriellen Schnittstelle ein, und bei Empfang eines Kommandos antwortet er falls notwendig. Hier denke ich sind Threads geeignet.
Stefan schrieb: > Nun ich denke genau Threads sind für mein Problem die Lösung. > Und zwar im THREAD_A scanne ich alle 5 Sekunden scanne ich einen Ordner > und bei einer Änderung sende ich etwas über die serielle Schnittstelle. Da wäre FAM (file alteration monitor) aber sinnvoller, als ein Thread. > Der THREAD_B liest zyklisch etwas auf der seriellen Schnittstelle ein, > und bei Empfang eines Kommandos antwortet er falls notwendig. Da wäre select() sinnvoll. > Hier denke ich sind Threads geeignet. Naajaa..
Stefan schrieb: > Nun ich denke genau Threads sind für mein Problem die Lösung. > Und zwar im THREAD_A scanne ich alle 5 Sekunden scanne ich einen Ordner > und bei einer Änderung sende ich etwas über die serielle Schnittstelle. > > Der THREAD_B liest zyklisch etwas auf der seriellen Schnittstelle ein, > und bei Empfang eines Kommandos antwortet er falls notwendig. > > Hier denke ich sind Threads geeignet. Ja. Auf jeden Fall "geeignet" im Sinne von "Du kommst ans Ziel". Auf Grund der Beschreibung klingt die Sache für mich eher nach einem klassischen Anwendungsfall für Single-Threaded mit select(2), außer da spielen noch andere Anforderungen mit rein. Peter Stegemann schrieb: >> Wenn ich mich recht entsinne wars der >> Kernel-Guru Alan Cox, der mal geäußert hat, dass Threads was für Leute >> sind, die keine State Machines (sauber) implementieren können. Und damit >> hat er möglicherweise auch garnicht so unrecht :-) > Alte Ausrede fuer Leute, die mit Threads nicht umgehen koennen... Ich denke Alan kann das :-) Stephan
Danke für den Tipp mit dem FAM. Leider gibt es kein Paket für meine
Zielhardware. Ich weiß noch nicht ob mir das Crosscompiling antue.
Welchen Vorteil hat ein FAM im Gegensatz zur manuellen Implementierung?
Derzeit prüfe ich alle 5 Sekunden die Modifizierungszeit des Ordners.
Bei einer Änderung zur vorigen Prüfung parse ich alle Dateien im Ordner.
Optimal wäre hier ein Timer, doch leider gibt es so etwas unter C nicht
:(
Sven P. schrieb:
> Da wäre select() sinnvoll.
Dazu habe ich eine Frage. Und zwar ich lese Strings zyklisch von der
seriellen mit getline() ein. Wenn ich das mit select() mache, könnte es
ja sein, dass die Zeile noch nicht vollständig übertragen worden ist,
select(() aber schon meldet, dass etwas gekommen ist, oder??
Hier am besten wieder mit getline() arbeiten und wenn die Zeile noch
nicht vollständig übertragen ist, liefert getline() einfach noch keine
Zeile??
> Danke für den Tipp mit dem FAM. Leider gibt es kein Paket für meine > Zielhardware. Ich weiß noch nicht ob mir das Crosscompiling antue. Naja, FAM setzt auch nur auf inotify auf. Das kannst du auch direkt benutzen. > Welchen Vorteil hat ein FAM im Gegensatz zur manuellen Implementierung? > Derzeit prüfe ich alle 5 Sekunden die Modifizierungszeit des Ordners. Bei FAM/inotify meldest du an, welche Verzeichnisse überwacht werden sollen, und sobald sich was ändert, wirst du benachrichtigt. Da der Kernel ja eh weiß, wenn sich was geändert hat, muß er nicht pollen. Die Wikipedia hat eine ganz gute Kurzbeschreibung von inotify: http://en.wikipedia.org/wiki/Inotify > Bei einer Änderung zur vorigen Prüfung parse ich alle Dateien im Ordner. Auch die, die sich nicht geändert haben? > Optimal wäre hier ein Timer, doch leider gibt es so etwas unter C nicht > :( Klar gibt's das. man setitimer man timer_create > Dazu habe ich eine Frage. Und zwar ich lese Strings zyklisch von der > seriellen mit getline() ein. Wenn ich das mit select() mache, könnte es > ja sein, dass die Zeile noch nicht vollständig übertragen worden ist, > select(() aber schon meldet, dass etwas gekommen ist, oder?? Ja. > Hier am besten wieder mit getline() arbeiten und wenn die Zeile noch > nicht vollständig übertragen ist, liefert getline() einfach noch keine > Zeile?? Wenn deine Schnittstelle nicht auf non-blocking eingestellt ist, wird die Funktion vermutlich so lange blockieren, bis eine ganze Zeile angekommen ist. Nun ist es aber auch nicht wirklich schwierig, stattdessen read() zu verwenden und das Zeilenende selber zu suchen.
Rolf Magnus schrieb: > Bei FAM/inotify meldest du an, welche Verzeichnisse überwacht werden > sollen, und sobald sich was ändert, wirst du benachrichtigt. Da der > Kernel ja eh weiß, wenn sich was geändert hat, muß er nicht pollen. > Die Wikipedia hat eine ganz gute Kurzbeschreibung von inotify: > http://en.wikipedia.org/wiki/Inotify Danke für den Hinweiß. Ich werde mal ein 2.6er Kernelsystem aufsetzten und mich mit inotify beschäftigen. Rolf Magnus schrieb: > Klar gibt's das. > man setitimer > man timer_create Danke auch für diesen Hinweiß. Die Timerfunktion löse ich mit einem Signalhandler der bei SIGVTALRM triggert. Rolf Magnus schrieb: > Wenn deine Schnittstelle nicht auf non-blocking eingestellt ist, wird > die Funktion vermutlich so lange blockieren, bis eine ganze Zeile > angekommen ist. Nun ist es aber auch nicht wirklich schwierig, > stattdessen read() zu verwenden und das Zeilenende selber zu suchen. Die Schnittstelle ist auf non-blocking eingestellt. Sollte also funktionieren =) Rolf Magnus schrieb: > Auch die, die sich nicht geändert haben? Derzeit ja. Mit inotify komme ich nicht zu der Datei die sich im beobachteten Ordner verändert hat, oder?? Danke für die super Hilfe!! lg Stefan PS: Die Zitat-Funktion finde ich super!
Ich würde das so machen das der Thread welcher das Lesen der Schnittstelle übernimmt, einfach von dem anderem Thread eine Nachricht erhält: Ich möchte den String XYZ senden. Der "Empfang und Sende Thread" kann dann diesen String über die Schnittstelle senden sobald Zeit dafür ist ohne das es zu Zugriffsproblemen kommt.
> Mit inotify komme ich nicht zu der Datei die sich im beobachteten Ordner > verändert hat, oder?? Doch. Wenn du ein ganzes Verzeichnis überwachst, bekommst du bei Änderung den Namen der Datei, die sich geändert hat und eine Maske, die angibt, um welche Art von Änderung es sich handelt. Dazu empfehle ich die man-Page von inotify:
1 | man 7 inotify |
Da ist das ganze ausführlich erklärt.
Läubi .. schrieb: > Ich würde das so machen das der Thread welcher das Lesen der > Schnittstelle übernimmt, einfach von dem anderem Thread eine Nachricht > erhält: Ich möchte den String XYZ senden. > Der "Empfang und Sende Thread" kann dann diesen String über die > Schnittstelle senden sobald Zeit dafür ist ohne das es zu > Zugriffsproblemen kommt. Ja, oder gleich einen dritten Thread: zwei wie gehabt, und wenn sie etwas senden wollen geht das an den dritten. Der sendet über RS232 und verteilt ggf. zurück die Antworten. Ich finde die Aufteilung auf mind. 2 Threads für so etwas alleine deshalb attraktiver, weil erstens die Funktionalitäten sauberer voneinander getrennt sind als wenn alles in eimem Brei um select herum vermatscht wird, und zweitens werden auch automatisch mehrere Kerne/CPUs genutzt.
Danke für all die Tipps!! Für die Interthread-Kommunikation gibt es ja mehrere Wege. Ich habe mich für Message Queues entschieden. Ist das so sinnvoll?
Beim SerialThread denke ich ist jedoch select() nicht sinnvoll. Denn dieser Thread soll ja schnell auf Nachrichten von der MessageQueue können. Hier ist pollen der Schnittstelle mit getline() doch besser, oder?
Vielleicht meint er nicht pollen, sondern blockierendes Lesen? Sonst kann er kaum schneller reagieren als mit select(). Hört sich jedenfalls nicht ganz stimmig an (Autor: Stefan (Gast)).
Also ich habe einen serialThread(). Der ist zuständig für das Senden und Empfangen über die Schnittstelle. Die Daten reicht der Thread mit Messages zu den Datenverarbeitenden Threads. Was gesendet wird empfängt der Thread per Messages. Hier mal ein Pseudocode:
1 | while(1) |
2 | {
|
3 | if(readline()) |
4 | sendMessage(line); |
5 | |
6 | if(receivedMessage()) |
7 | writeSerial(msg) |
8 | }
|
Wenn ich blockierend lese oder es mit select löse, Timeout zB 500ms, kann writeSerial() nicht schnell reagieren. Das meine ich. Hier wären doch zwei Threads notwenig. Einer zum Senden und einer zum Schreiben. Jedoch bin ich somit wieder beim Usprungsproblem.
Sehe ich das richtig, daß sowohl sendMessage(line) als auch receivedMessage() nichtblockierend sind und du in einer Endlosschleife beide abwechselnd abfragst, nur um in aller Regel festzustellen, daß nichts los ist?
nur zur Sicherheit: Wen du bei select() einen timeout angibst, dann heisst das nicht, daß select() wirklich solange wartet. Vielmehr wartet es höchstens solange, springt aber schon vorher zurück, wenn einer der übergebenen fd heiß wird. Genau dafür ist select() ja da.
Hallo Klaus, Genau so ist es. Deswegen dachte ich zwei Threads, und jeweils eine blockierende Funktion. Jedoch weiß ich nicht wie es sich verhält, wenn readline() blockiert, und eine Message zum sendThread() kommt und der senden will.
Es ist natürlich Unfug, in dem Thread, der für den anderen die Antwort senden soll, zu blockieren. Ich sehe auch nicht ein, wieso ein Thread unbedingt zwei grundverschiedene Dinge machen soll. Deshalb mein Vorschlag mit den 3 Threads: einer kümmert sich nur ums Senden und bekommt seine Aufträge von den anderen beiden. Andere Variante: beide Threads können über die serielle schreiben und stimmen sich ggf. mit einem Mutex ab, oder dritte Variante: select(), wobei ich nicht verstehe, was daran langsam sein soll. Eine Endlosschleife mit nonblocking fd ist aber mit Sicherheit die ungeschickteste Lösung.
Und die Threads wollen auch koordiniert werden, was wieder Mutexen oder Semaphoren oder sonstigen Overhead anschleppt. Grad das gegenseitige Signalisieren ist weniger trivial, als man annehmen mag.
Hab die 2. Nachricht noch gesehen. Und zwar im readThread arbeite ich mit select(). Wenn etwas reinkommt, bricht select() ab und ich kann auf die eingehende Zeile reagieren. Der sendThread empfängt eine Nachricht (blockierend) und will senden, dadurch bricht select im readThread ab, und die Schnittstelle ist frei. Hab ich das so richtig verstanden?
@Sven: je nachdem, wie sie plaudern. Der dritte, der nur versendet, kann doch recht problemlos immer erst eine Nachricht komplett schicken, bevor er die andere anfasst. Man muß es sicher nicht mit dem dritten Thread machen, 100% CPU-Last zum Pollen ist bestimmt nicht der beste Weg.
1 | Variante einfach modular effizient 1 Kern effizient Mehrkern |
2 | --------------+----------+---------+-----------------+-------------------- |
3 | select | + | 0 | ++ | 0 |
4 | --------------+----------+---------+-----------------+-------------------- |
5 | polling mit | | | | |
6 | nonblocking | ++ | -- | -- | -- |
7 | --------------+----------+---------+-----------------+-------------------- |
8 | 2 Threads, | | | | |
9 | beide schrei- | 0 | + | ++ | + |
10 | ben, Mutex | | | | |
11 | --------------+----------+---------+-----------------+-------------------- |
12 | 3 Threads | 0 | ++ | ++ | ++ |
13 | --------------+----------+---------+-----------------+-------------------- |
Stefan schrieb: > Hab die 2. Nachricht noch gesehen. > > Und zwar im readThread arbeite ich mit select(). Wenn etwas reinkommt, > bricht select() ab und ich kann auf die eingehende Zeile reagieren. > > Der sendThread empfängt eine Nachricht (blockierend) und will senden, > dadurch bricht select im readThread ab, und die Schnittstelle ist frei. > > Hab ich das so richtig verstanden? Keine Ahnung, ich habe deine Beschreibung nicht verstanden.
Klaus Wachtler schrieb: > Eine Endlosschleife mit nonblocking fd ist aber mit Sicherheit > die ungeschickteste Lösung. Bin ich auch deiner Meinung. Klaus Wachtler schrieb: > je nachdem, wie sie plaudern. > Der dritte, der nur versendet, kann doch recht problemlos > immer erst eine Nachricht komplett schicken, bevor er die > andere anfasst. Ist durch select() im readThread() jedoch die Schnittstelle blockiert? Kann der sendThread() senden, wenn im anderen Thread select() noch ausgeführt wird, oder wird, sobald der sendThread() senden will, automatisch selct abgebrochen, eben weil sich auf der Schnittstelle was tut?
Klaus Wachtler schrieb: > @Sven: > je nachdem, wie sie plaudern. > Der dritte, der nur versendet, kann doch recht problemlos > immer erst eine Nachricht komplett schicken, bevor er die > andere anfasst. Ich meinte jetzt die Methodik, mit der ein Thread einen anderen anschubst.
Sven P. schrieb: > Ich meinte jetzt die Methodik, mit der ein Thread einen anderen > anschubst. Naja, da gibt es ja jetzt mehrere Varianten.
Stefan schrieb: > Ist durch select() im readThread() jedoch die Schnittstelle blockiert? > Kann der sendThread() senden, wenn im anderen Thread select() noch > ausgeführt wird, oder wird, sobald der sendThread() senden will, > automatisch selct abgebrochen, eben weil sich auf der Schnittstelle was > tut? select in einem Thread verhindert nicht das Benutzen des fd in einem anderen. Im Gegenteil: select() bekommt ohnehin die zu überwachenden fds in je einem Satz für zu lesende fds, zu beschreibende fds und fds für out of band data. In den Satz mit den zu lesenden trägst du deine RS232 ein. Das ist komplett davon unabhängig, ob du auf demselbem fd etwas schreibst. select() springt zurück, wenn von diesem fd etwas ohen zu blockieren gelesen werden kann.
das Ganze übrigens nur für *X, nicht Windows... Das scheint hier aber gegeben zu sein.
Danke für all die Hilfe! Nach dem Jahreswechsel habe ich mich wieder an den PC gesetzt und es umgesetzt =) Inotify kann ich leider nicht benutzen, denn dafür wird der 2.6er Kernel benötigt und der ist leider nicht kompatibel mit meiner Hardware. Ich werde dies mit dnotify machen. Leider ist das nicht so mächtig wie inotify. Welche Datei sich nun geändert wird nicht mitgeteilt. Das neue parsen aller Files stört mich eigentlich nicht, denn a) sind die Files klein (100 Bytes), b) wenig vorhanden (< 30 Files) und c) kommt das ChangeEvent sehr selten (max. 1x am Tag). lg Stefan
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.