Pthreads variable teilen...
-
Hallo!
Mir ist leider kein bessere Titel eingefallen. Soweit ich gesehen hab, gibts aber so eine Frage noch nicht hier im Forum..
Also:
Ich habe einen Echtzeitthread und eben das Hauptprogramm (+gui und so zeug...) und meine Frage ist ob es okay ist auf eine variable nur lesend aus dem Realtime Thread zuzugreifen (volatile deklariert) und sie aus dem Hauptthread heraus zu setzten ohne mutexen (?) zu verwenden...Meiner Logik nach müsste das hinhauen, aber sicher bin ich mir nicht... also es wird aus dem Realtime Thread niemals geschrieben... nur möcht ich ungern den Thread (der alle 50 ns was zu tun hat) unterbrechen, da das ganze ne Echtzeitmessung ist...
Also Plan B würde ich trylock verwenden... und einfach die variable nicht auslesen wenn der mutex grad gelockt ist... aber gefallen tut mir das auch nicht wirklich...
(In wirklichkeit wird das ganze noch ein bisschen häßlicher, weil ich in einem Teil (des Realtime Threads) auch schreibend zugreifen will, aber das ist in der initialisierungsphase, und da verwende ich conditional variables...)
-
Nein, das ist nicht in Ordnung. Compiler und die CPU können Loads/Stores beliebig umordnen. Daher kann es passieren, dass du in dem einen Thread die Variable änderst und in dem anderen Thread nie etwas davon mitbekommst oder nur blödsinnige Werte.
Atomare Variablen helfen dir hier vielleicht.
Siehe auch http://www.youtube.com/watch?v=mrvAqvtWYb4
-
Hi!
Erstmals danke für deine Hilfe, hab überhaupt nicht daran gedacht gehabt was da alles schief gehen kann.. Hab jetzt längere Zeit entweder zeitunkritisches gemacht, oder auf einfachen mikrokontrollern gearbeitet (ohne parallelität [bis auf die verschiedenen Einheiten darauf wie UART etc.]) und da hat meistens ein volatile ausgereicht damit es zu keinen bösen überraschungen kommt.
Also nachdem ich mir das video angesehen hab bin ich irgendwie trotzdem nicht wirklich schlauer also vorher...
Vielleicht mal ein bisschen zusatzinfo: Es geht um einen Messthread der eine Statusvariable besitzt. Der Messthread liest den Status und macht je nachdem verschiedene Sachen... im Wesentlichen gibts nur IDLE (also nichts machen) STARTUP (da wird alles initialisert; hier setzt er auch selber auf RUN, aber da würde ich nen mutex verwenden...). Der Hauptthread setzt im prinzip nur den status auf STARTUP, beziehungsweise vielleicht auf IDLE... mehr nicht...
Jetzt hab ich nur das Problem, das ich beim gcc nur ++ und -- und += und ein paar andere atomic instructions gefunden hab, aber kein setzten und kein laden.. gut, laden hab ich schon ein paarmal also 'add 0 and fetch' gesehen, aber das kann ja nicht alles sein? Also um das nochmal klarzustellen, ich mach aus dem Hauptthread wirklich ausschließlich write operations, also kein lesen oder incrementieren.
Es spielt keine Rolle wie lange es dauert bis der Messthread mitkriegt dass der Hauptthread den status geändert hat. Schlimm wäre nur wenn der Messthread einen falschen Wert lesen würde (wenn LOAD und STORE vielleicht gleichzeitig auftreten???).Wenn das wirklich möglich ist, reicht es dann nur die LOAD Befehle als 'add 0 & fetch' zu implementieren oder gibt es auch ne möglichkeit den Wert einer Variable atomar zu setzten??
So wie ich den Code übernommen hab waren da absolut keine Mechanismen zur Synchronisation enthalten. Jetzt muss ich halt schauen, dass (mit einigen anderen Änderungen die den Code lesbarer & wartbarer machen sollen) das ganze trotzdem ähnliche Leistungsfähig sein sollte... und mutexen zu benutzen scheint ja angeblich doch in erheblichen overhead auszuarten...
Werd mich dann mal weiter umsehen was es noch so gäbe...
-
In C++0x gibt es std::atomic<>. Neuere GCCs bieten das bereits an.
Ansonsten hat der GCC noch folgende Builtins http://gcc.gnu.org/onlinedocs/gcc-4.4.1/gcc/Atomic-Builtins.html
-
Hallo,
ich hab zu dem Thema noch eine Frage: muss man wirklich auch Mutexe setzen bei
Variablen, die man NUR ausliest?Bspw. ich habe einen konstanten globalen Wert irgendwo gespeichert, und will
diesen nun von versch. Threads immer wieder mal abfragen. Ich habe in dieser
Situation noch NIE Mutexe verwendet und bisher nie damit Probleme gehabt. Afair
sind solche Operationen (int) sowieso von Haus aus atomic. Taeusche ich mich? Wenn
ja, wo liegt mein Denkfehler?? Warum sollte ich reines lesen per Mutex
synchronisieren?
-
paralleles Lesen (zb. von Konstanten) ist prinzipiell kein Problem - man kann nur nicht zuverlässig lesen wenn parallel auch darin geschrieben wird.
-
naaachfrager schrieb:
Afair
sind solche Operationen (int) sowieso von Haus aus atomic. Taeusche ich mich?Wie DrGreenthumb schon gesagt hat, ist es egal solange du nur liest und nichts geschrieben wird. Aber Operationen auf int sind nicht automatisch atomic! Wenn der Integer nicht in einem Register ist, hast du ja immer noch Loads/Stores aus dem Speicher.
-
Aber nochmal:
Wenn ich nur var = value; im einen thread mache und im anderen nur if(var == KONST_1) oder dergleichen kann es dann zu einem problem kommen?
Also Probleme wären für mich: der 2. thread ließt einen falschen Wert aus, der lesende Thread überschreibt irgendwie die Änderung des 1. Threads...
WANN der Thread die Änderung mitkriegt ist ja egal... also ob der mess thread noch 5 messdurchläufe macht oder nicht ist egal bevor er idlen geht... alles was konfiguration betriff ist mit mutexen gelöst... es geht nur um diese status variable...
Leider unterstützt meine version vom gcc atomic<> noch nicht.. angeblich unterstützt nichtmal gcc 4.5 (ich hab 4.3) atomic<> oder ich mach irgendwas falsch dabei...
Das wär natürlich die beste Lösung... hab schon drann gedacht einfach ein typedef zu machen für atomic_int und später dann einfach typdef atmoic<int> atomic_int zu machen...
Trotzdem interessiert mich ob es bei meiner Lösung wirklich zu Problemen kommen kann... (wie gesagt, kein increment oder so zeugs [a++, a+=5, ...] oder dergleichen... nur Load & Store)
Tut mir leid wenn ich mich wiederhole aber es kommen dann doch immer wieder andeutungen wo ich mir denk dass es vielleicht doch okay ist es so zu machen...
Aja, und danke für all euere Antwortposts... das Forum ist echt Klasse... *schleim schleim*
-
Manuelh87 schrieb:
Wenn ich nur var = value; im einen thread mache und im anderen nur if(var == KONST_1) oder dergleichen kann es dann zu einem problem kommen?
Ja.
Trotzdem interessiert mich ob es bei meiner Lösung wirklich zu Problemen kommen kann... (wie gesagt, kein increment oder so zeugs [a++, a+=5, ...] oder dergleichen... nur Load & Store)
Egal. Wie rüdiger schon sagte ist das idR. nicht atomisch.
Tut mir leid wenn ich mich wiederhole aber es kommen dann doch immer wieder andeutungen wo ich mir denk dass es vielleicht doch okay ist es so zu machen...
Naja, es muss eben nicht immer Schwierigkeiten geben, aber früher oder später wird es Schwierigkeiten machen. Willkommen in der wunderbaren Welt des Multithreadings.
-
Wenn ich nur var = value; im einen thread mache und im anderen nur if(var == KONST_1) oder dergleichen kann es dann zu einem problem kommen?
Wenn var die Variable ist, die in beiden Threads verwendet wird ... dann Ja. Wurde aber schon gesagt.
der lesende Thread überschreibt irgendwie die Änderung des 1. Threads...
Warum sollte der lesende Thread irgendetwas schreiben?
Tut mir leid wenn ich mich wiederhole aber es kommen dann doch immer wieder andeutungen wo ich mir denk dass es vielleicht doch okay ist es so zu machen...
Der Zugriff auf gemeinsam benutzte Variablen muss synchronisiert werden, falls auch nur einer der Threads die Variable veraendert.
-
Hi!
Ich hoffe es ist kein Problem dass ich den 5 monate alten thread nochmal ausgrabe... aber ich hätt da noch ein paar Fragen:
-
std::atomic<> kann ich nirgendst finden... hab sie jetzt nicht parat, aber auf na seite vom gcc stand dass er sie noch nicht unterstützt.. also version 4.5 glaub ich... (oder wars 5.5? das gibts noch nicht, oder???)
die built ins funktionieren, aber soll ich da dann wenn ich einfach nur die variable lesen will __sync_fetch_and_add(ptr, 0) machen??
Und wenn ich sie schreiben will das mit compare and swap?? -
eine andere möglichkeit für eine art state variable (in welchem zustand ist der realtime-thread gerade) will ich unbedingt vermeiden dass mutexen mir das timing zamhauen... ich will ihn nicht jedes mal locken müssen... (wenn das oben passt, dann kann ich eh das nehmen... das sollte ja dann wenig zeit kosten im vergleich mit nem mutex...)
Die Idee war, nachdem mir ja nur wichtig ist dass der realtime thread schnell ist (aber nicht unbedingt schnell auf änderungen in der state variable reagieren muss) das man hier vielleicht mit signalen arbeiten könnte... ich sende dem thread ein signal und er unterbricht dann irgendwann und dort wird alles schön mit mutexen dann geschützt...
Ich hauen wenn das mit den signalen bei posix threads nicht geht... ich hab mir das noch nicht im detail angesehen... aber vielleicht kennt sich da jemand damit aus... mir wär aber variante 1 eh lieber weils ein bisschen sauberer wirkt, meines erachtens...
Danke schonmal im voraus...
mfg Manuel
-
-
Hi Manuel,
ich hoffe auch, daß es kein Problem ist, wenn jemand erst nach weiteren 6 Monaten antwortet
Ich glaube, daß ich Deine Nachfragen gut verstehen kann. Mir ist nicht bekannt, daß das es ein Problem darstellt, wenn Du von einem Thread eine Variable ließt die ein anderer Thread schreibt, sofern es sich dabei um eine "volatile-int" deklaration handelt.
Du schreibst auch, daß es Dir egal ist, wann der lesende Thread den geschriebenen Wert mitbekommt. Natürlich kann es sein, dass der schreibende Thread den Wert von seinem CPU Register in den Speicher erst nach ein paar weiteren Taktzyklen schreibt und der lesende Thread somit noch ein paar mal den alten Wert gelesen hat, obwohl er schon anders sein könnte. Aber das ist Dir ja egal. Dass der lesende Thread aber einen völlig willkürlichen Wert vorfinden kann, muss mir jemand erklären wie das gehen soll. Das, was Du machst nennt sich im weitesten Sinne ein Spinlock und wird auch im Linux-Kernel so gemacht.
Bei einem Spinlock looped ein Thread auf einer Variablen, bis sie den gewünschten Wert hat. Ein anderer Anwendungsfall ist z.B. auch der Backery-Algorithmus, bei dem ein Semaphore per Spinlocks so simuliert wird, ohne auf spezielle CPU-Mittel angewiesen zu sein. Ich glaube die Verwirrung um das Theam dreht sich darum, daß Du Dich vielleicht nicht deutlich genug auf "int" oder "kleiner als int" festgelegt hast. Würdest Du z.B. eine struct nehmen, muss die schreibende CPU tatsächlich mehrere Schritte zum Schreiben in den Speicher durchführen. Und das kann u.U. zu sehr schrägen Konstrukten im Maschinencode führen und schließlich greift der lesende Thread mitten drin rein. Es muss aber nicht mal ein struct sein, selbst ein long kann soetwas verursachen, einfach weil zum Lesen und Schreiben mehrere Maschinenbefehle notwendig sind. Bei einem "normalen volatile int" ist mir das von keiner CPU bekannt (zu "normal" meine ich nicht an krummen Adressen oder Packed-Structs). So braucht zwar z.B. eine PowerPC-CPU zum Laden der Memoryadresse der int-Variablen in ein Register mehrere Befehle (es werden zunächst die oberen Bits der Adresse in den unteren Teil eines Registers geladen, dann nach link geschiftet und die nächsten Bits per XOR in das selbe Register, wieder shiften usw. bis die Adresse im Register ist), aber antschließend wird mit einer Instruktion der Wert der in der Speicheradresse steht, die in dem zuvor beschriebenen Register steht in ein weiteres Register geladen und fertig. Das Zurückschreiben funktioniert analog. Wie gesagt, bei "int" und "kleiner int".
Um ganz sicher zu gehen würde ich Dir natürlich empfehen das Disassambly anzuschauen, was Du Dir mit dem GCC erzeugen kannst.
Multi-Threading ist in C/C++ aber insgesamt eine ziemlich verzwickte Sache. Ich stelle immer wieder fest, daß Entwickler nicht wissen, worüber man sich alles Gedanken machen muss. z.B. die Frage: Kann ein "new" zu Problemen führen ? Nur mal so als Hinweis