Forum: PC-Programmierung Mutex nötig?


von Lars (Gast)


Lesenswert?

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
1
static DiagResult updateBufferA(const uint8_t* const dataIn, const uint8_t* const dataOut, const uint8_t firstVal, uint8_t* lastRead)
2
{
3
  uint8_t counter = 0;
4
... ... ...
5
}
6
7
8
static DiagResult updateBufferB(const uint8_t* const dataIn, const uint8_t* const dataOut, const uint8_t firstVal, uint8_t* lastRead)
9
{
10
  uint8_t counter = 0;
11
... ... ...
12
}

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)

von B. W. (yesitsme)


Lesenswert?

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".

von Til S. (Firma: SEGGER) (til_s)


Lesenswert?

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.

von Lutz (Gast)


Lesenswert?

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).

von Rolf M. (rmagnus)


Lesenswert?

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.

von Lars (Gast)


Lesenswert?

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

von 🐧 DPA 🐧 (Gast)


Lesenswert?

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.

von Til S. (Firma: SEGGER) (til_s)


Lesenswert?

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.

von Noch ein Kommentar (Gast)


Lesenswert?

> 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.

von MaWin (Gast)


Lesenswert?

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.

von c-hater (Gast)


Lesenswert?

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.

von Rolf M. (rmagnus)


Lesenswert?

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.

von MaWin (Gast)


Lesenswert?

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.

von Alonzo Mutex (Gast)


Lesenswert?

Watch my Name.

MaWin hat recht.

von MaWin (Gast)


Lesenswert?

Eben.
Ich habs drauf.

von Ploppi (Gast)


Lesenswert?

"Solange man Mutexe nicht verploppt ist alles gut" (Zitat von einem 
Programmiererkollegen)

von Klaus S. (kseege)


Lesenswert?

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.

von Carl D. (jcw2)


Lesenswert?

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.

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.