Tag,
ich habe zwei Threads, die die jeweils eine Funktion aufrufen. Die
Funktionen machen genau das selbe. Nur eine ist für threadA und die
andere für threadB
Es werden nur die Parameter verwendet, die auch übergeben werden, sowie
die counter variable.
Da wie gesagt beide genau das selbe machen, wollte ich eine löschen und
die Funktion dann nur updateBuffer nennen.
Muss diese dann durch ein Mutex gesichert werden?
Was passiert mit der counter variable, wenn erst threadA die Funktion
aufruft und befor dieser fertig ist die Funktion von threadB aufgerufen
wird?
Oder muss mutex nur gemacht werden, wenn globale variablen verwendet
werden?`(also die Deklaration von uint8_t counter außerhalb der
Funktion)
counter ist eine lokale Variable in der Funktion und landet auf dem
Stack. Da jeder Thread einen eigenen Stack, ist es kein Problem.
Problematisch wird nur, wenn du 2 Threads hast, die auf die selben Daten
zugreifen müssen. Wie z.B. globale Variablen. Da musst du dir dann
Gedanken machen, wer wann schreiben darf, ohne dem anderen "den Teppich
unter den Füßen wegzuziehen".
Nein, du brauchst kein Mutex.
Alle Parameter plus die lokale Variable counter liegen auf dem
jeweiligen Thread Stack (bzw. in Registern). Damit ist die Funktion
updateBuffer thread-safe (vorausgesetzt du machst nicht noch andere
problematische Sachen in der Funktion). Selbst wenn updateBuffer
preemptiv unterbrochen wird werden die Register gesichert/restauriert
und der Thread Stack nicht von dem anderen Thread verändert. Der Thread
bekommt also nichts davon mit das zwischendurch der andere Thread lief.
Würde es nicht nur auf globale Variablen beschränken, sondern auch
gleicher Speicherbereich. Da fällt mir bei Dir die dataOut und lastRead
Variablen auf. Hängt davon ab, wie diese deklariert sind und was den
Threads übergeben wird.
(Das gleiche Problem hättest Du natürlich auch bei den getrennten
Funktionen gehabt).
Til S. schrieb:> Nein, du brauchst kein Mutex.>> Alle Parameter plus die lokale Variable counter liegen auf dem> jeweiligen Thread Stack (bzw. in Registern).
Die Parameter sind Zeiger. Wenn die auf die selben Daten zeigen, kann es
sehr wohl nötig sein, die Zugriffe mit einem Mutex abzusichern.
Rolf M. schrieb:> Die Parameter sind Zeiger. Wenn die auf die selben Daten zeigen, kann es> sehr wohl nötig sein, die Zugriffe mit einem Mutex abzusichern.
Die Parameter sind parameter vom Thread selber.
Dann kann ich also ohne Problem eine Funktion löschen.
Da war ich mir nicht ganz sicher.
Danke
Wenn beide Funktionen das gleiche machen, und auf keine globalen
Variablen zugreifen (das beinhaltet auch static variablen), kann man in
der Regel eine Löschen, ja. Da musst du dir keine neuen Sorgen um
locking machen.
Um deine lokale counter Variable musst du dir keine Sorgen machen. Die
sind bei den 2 Threads nicht die selben.
Was du noch beachten musst, ist, wohin die Pointer Parameter zeigen.
Wenn do irgendwo einen Pointer hast, auf den gleichen Speicher, und auf
den zugreifst, kann jenachdem locking nötig werden. Aber das kann man
nicht so allgemein beurteilen.
Grundsätzlich kann man sagen, werden in einem Thread Daten modifiziert,
die du im anderen brauchst, brauchst du einen Mechanismus, um zu
schauen, dass die sich nicht in die quere kommen. Bei einem simplen
gemeinsamen Referenz Counter reicht manchmal eine Atomare variable, und
etwas logik um sicherzustellen, dass die nie zu früh 0 wird. Wenn man in
irgend einen gemeinsamen Ringbuffer schreibt & liest, braucht man
eventuell etwas mehr als dass, und nimmt einen Mutex Lock. Aber eben, so
generell kann man das eigentlich nicht sagen, es gibt immer viele Wege,
ein Problem zu lösen oder zu vermeiden.
Rolf M. schrieb:> Die Parameter sind Zeiger. Wenn die auf die selben Daten zeigen, kann es> sehr wohl nötig sein, die Zugriffe mit einem Mutex abzusichern.
Korrekt, das hatte ich jetzt mal implizit angenommen. Guter Hinweis.
Aber scheint in dem Fall kein Problem zu sein wenn ich den TO richtig
verstehe.
> Aber scheint in dem Fall kein Problem zu sein...
Dann geben wir den Ratschlag: Wenn du einen Zeiger auf ein Objekt
übergibst und nicht weißt, ob es ein Problem ist - schau in der
Dokumentation nach. Wenn es dort nicht steht, nimm eine andere Library.
Lars schrieb:> Dann kann ich also ohne Problem eine Funktion löschen.> Da war ich mir nicht ganz sicher.
Es ist ein gängiger Denkfehler anzunehmen, ein Mutex würde eine Funktion
oder eine Codeausführung gegen eine andere schützen.
In Wirklichkeit werden gemeinsame Daten geschützt.
Wenn es keine zwischen den Threads gemeinsamen Daten gibt, wird auch
kein Mutex benötigt.
MaWin schrieb:> Es ist ein gängiger Denkfehler anzunehmen, ein Mutex würde eine Funktion> oder eine Codeausführung gegen eine andere schützen.> In Wirklichkeit werden gemeinsame Daten geschützt.> Wenn es keine zwischen den Threads gemeinsamen Daten gibt, wird auch> kein Mutex benötigt.
Das ist halber Unsinn. Halb deshalb, weil es natürlich letztlich darum
geht, Daten konsistent zu halten. Das aber hat der Mutex mit
SÄMTLICHEN anderen softwaremäßigen Synchronisationsmechanismen
gemeinsam. Keiner davon schützt gegen konkurrierende Codeausführung.
Auch nicht "critical sections", falls du das glaubst...
Letztlich beruhen alle diese Mechanismen darauf, den Code anzuhalten,
wenn die zu verwendende Resource belegt ist. Und das geschieht immer
durch Abfrage, ob die Resource belegt ist und einen expliziten Aufruf
einer Wartefunktion, wenn sie belegt ist.
Echte Code-Konkurrenz gibt es nur auf "Treiber-Ebene". In Interrupts.
c-hater schrieb:>> Wenn es keine zwischen den Threads gemeinsamen Daten gibt, wird auch>> kein Mutex benötigt.>> Das ist halber Unsinn.
Nein, das ist korrekt, wobei man es von "Daten" auf "Ressourcen"
erweitern sollte.
> Halb deshalb, weil es natürlich letztlich darum geht, Daten konsistent zu> halten. Das aber hat der Mutex mit SÄMTLICHEN anderen softwaremäßigen>Synchronisationsmechanismen gemeinsam.
Es ging aber nicht darum, wie synchronisiert werden muss, sondern
ob.
> Letztlich beruhen alle diese Mechanismen darauf, den Code anzuhalten,> wenn die zu verwendende Resource belegt ist.
Nein, Atomics halten nix an.
c-hater schrieb:> Das ist halber Unsinn.
Nein, ist es nicht.
Ich sprach von der Denkweise, die man anstellen sollte, wenn man über
Mutexen nachdenkt. Nicht über die interne Implementierung von Mutexen.
Die "Datendenkweise" ist deutlich zielführender und auch einfacher, als
die Critical-Section-Denkweise.
Es ist deutlich einfacher ein gut durchdachtes Locking zu entwickeln,
wenn man in Daten-Locks statt Code-Locks denkt.
> Letztlich beruhen alle diese Mechanismen darauf, den Code anzuhalten,> wenn die zu verwendende Resource belegt ist. Und das geschieht immer> durch Abfrage, ob die Resource belegt ist und einen expliziten Aufruf> einer Wartefunktion, wenn sie belegt ist.
Nein. z.B. Sequence-Locks funktionieren ohne Wartefunktion.
> Echte Code-Konkurrenz gibt es nur auf "Treiber-Ebene". In Interrupts.
Ehm... Nein.
c-hater schrieb:> Echte Code-Konkurrenz gibt es nur auf "Treiber-Ebene". In Interrupts.
Das halte ich für ein Gerücht. Alle meine Interrupts tauschen Daten über
das Producer/Consumer-Schema mit 1 (in Worten einem!) Treiber ohne jedes
Locking und ohne Fehler aus.
Meine Interprozesskommunikation mit "shared memory" zwischen 25
Teilnehmern ohne jeden Interrupt kommt dagegen ohne Mutex nicht
fehlerfrei zustande.
Been there, done that.
Klaus S. schrieb:> c-hater schrieb:>> Echte Code-Konkurrenz gibt es nur auf "Treiber-Ebene". In Interrupts.>> Das halte ich für ein Gerücht.
Ich auch, aber offenbar hat der Gute noch nichts von
Multiprozessorrechnern gehört. Schon die /370 auf der ich vor 33J in's
Programmieren für den Lebensunterhalt eingestiegen bin, hatte 4 CPU's
die um den Hauptspeicher gekämpft haben. Heute ist das längst auf
Microcontrollern, die auch von Amateuren genutzt werden, angekommen.
Aber noch nicht bei allen.