Hallo, ich habe eine Datenklasse, die zahlreiche Setter- und Gettermethoden hat, die aus verschiedenen Threads aufgerufen werden. In allen Setter- und Gettern wird mit einem Mutex gesperrt. Manche Setter rufen intern andere Setter auf (die aber auch direkt zur Verfügung stehen sollen), so dass manchmal in dem Geschachtel Deadlocks entstehen und nichts mehr geht. Ich würde rekursive Mutexes nehmen, aber die gibt es auf dem System nicht (sehr kleines Linux). Manche sagen ja sogar dass rekursive Mutexes ein schlechtes Design sind. Welche Möglichkeiten gäbe es sonst noch? Werner
Werner schrieb: > Welche Möglichkeiten gäbe es sonst > noch? bei Windows kann man mit Critital Section arbeiten, die blockiert sich im gleichen Thread nicht, ist sogar schneller als ein Mutex. Sonst ist es meist keine gute Idee ein Objekt innerhalb von sich selber Threadsave zu machen, das wird üblicherweise außerhalb gemacht. Wenn man nur mit einen Thread darauf zugreift, kosten die sperren nur sinnlos Ressourcen. Nur der externe kann wissen wie er das Objekt verwendet.
Peter II schrieb: > bei Windows Werner schrieb: > aber die gibt es auf dem > System nicht (sehr kleines Linux).
Werner schrieb: > ... Ich würde rekursive Mutexes nehmen, aber die gibt es auf dem > System nicht (sehr kleines Linux). Manche sagen ja sogar dass rekursive > Mutexes ein schlechtes Design sind. Welche Möglichkeiten gäbe es sonst > noch? > > Werner Hast du keine Möglichkeit rekursive Mutexe in deinem Linux nachzurüsten ? Critical sections haben leider den Nachteil, das alle Prozesse beim betreten der Section angehalten werden und nicht nur die, die die Section ebenfalls betreten wollen. Ob eine rekursive Mutex ein schlechtes Design darstellt ist eine Frage des spezifischen Anwendungsfalls und kann nicht pauschal beantwortet ist. Generell gilt, wenn es ein besseres Design zur Lösung eines Problems gibt, dann sollte man es auch nehmen. Und was besser ist, hängt von den individuellen Randbedingungen und den Prioritäten ab (Zeit, Geld, Wartbarkeit, Testbarkeit, ...)
The D. schrieb: > Critical sections haben leider den Nachteil, das alle Prozesse beim > betreten der Section angehalten werden und nicht nur die, die die > Section ebenfalls betreten wollen. nein, wie soll denn den Prozessen anhalten? Es blockiert doch nur der Aufruf "EnterCrititalSection", wenn jemand anders schon drin ist. Der Ansatz von Werner ist schon falsch, die sperre sollte vom Aufrufer erfolgen schon ist sein Problem komplett verschwunden.
>Nur der externe kann wissen wie er das Objekt >verwendet. ...und deswegen brauche ich doch eigentlich eine "objektglobale" Sperre, also einen Mutex der IN meinem Objekt sitzt?
Hallo Werner, Werner schrieb: > Manche Setter rufen intern > andere Setter auf (die aber auch direkt zur Verfügung stehen sollen), so > dass manchmal in dem Geschachtel Deadlocks entstehen und nichts mehr > geht. Da hier nur ein mutex im Spiel zu sein scheint, kann das kein deadlock sein. Dein Problem ist ein double lock. So etwas lässt sich extrem einfach vermeiden: Der mutex wird immer nur in einer öffentlichen Funktion gelocked. Öffentliche Funktionen werden intern nicht aufgerufen. Für den Fall, dass eine öffentliche Funktion intern verwendet werden muss, wird sie aufgeteilt in einen öffentlichen Teil, der nur den mutex locked und eine Implementierung, die nur mit gelocktem mutex aufgerufen wird. Beispiel:
1 | class foo { |
2 | public: |
3 | int a() const |
4 | { |
5 | std::lock_guard<std::mutex> lock( mutex_ ); |
6 | |
7 | return a_ + b_impl(); |
8 | } |
9 | |
10 | int b() const |
11 | { |
12 | std::lock_guard<std::mutex> lock( mutex_ ); |
13 | |
14 | return b_impl(); |
15 | } |
16 | private: |
17 | int b_impl() const |
18 | { |
19 | return a_ + b_; |
20 | } |
21 | |
22 | mutable std::mutex mutex_; |
23 | |
24 | int a_; |
25 | int b_; |
26 | }; |
> Ich würde rekursive Mutexes nehmen, aber die gibt es auf dem > System nicht (sehr kleines Linux). Manche sagen ja sogar dass rekursive > Mutexes ein schlechtes Design sind. recursive mutexes sind Mist, weil sich das obige Problem ganz einfach ohne recursive mutexes lösen lässt. Wenn ich dead locks verhindern möchte, dann brauche ich eine Lock-Hierarchie. Daraus ergibt sich eine Reihenfolge, in der ich 2 oder mehr mutexe locken muss, damit keine dead locks auftreten können. Wenn ich an irgend einer Stelle in der Software nicht mehr sagen kann, welchen mutex ich schon gelocked habe, dann kann ich auch keine dead locks verhindern. Ein recursive lock löst also kein Problem, ist aber teurer, da er intern Buch über lock count und lock owner führen muss und diese Informationen auf synchronisieren muss. mfg Torsten
Wenn man mehrere Mutexe bzw. Semaphore verwendet, kann man Deadlocks dadurch verhindern, dass das Belegen in allen Kontexten in derselben Reihenfolge erfolgt und das Freigeben umgekehrt dazu. Man kann in den Namen des Mutex z.B. einen numerischen Teil aufnehmen, um die Angelegenheit übersichtlicher zu machen. Ebenso kann man sich ggf. Wrapper basteln, in denen mit Hilfe von Assertions eine falsche Reihenfolge beim Belegen oder Freigeben erkannt und beanstandet wird.
Andreas S. schrieb: > Wenn man mehrere Mutexe bzw. Semaphore verwendet Worin besteht denn der Unterschied zw. Mutexen und Semaphoren?
Schaukasten schrieb: > Andreas S. schrieb: >> Wenn man mehrere Mutexe bzw. Semaphore verwendet > > Worin besteht denn der Unterschied zw. Mutexen und Semaphoren? Ein Mutex ist eine binäre Semaphore, bei der noch zusätzlich die Regel gilt, dass die Inkrement- / Dekrement-Operationen Paarweise vom selben thread / process aufgerufen werden (der thread, der den mutex locked, unlocked ihn auch wieder).
Werner schrieb: > Manche sagen ja sogar dass rekursive Mutexes ein schlechtes Design sind. Ja, sie sind ein Hinweis auf schlechtes Design. Der Grund: Mit einem Mutex willst du eine Invariante schützen. Beispiel: Funktion A ruft Funktion B auf, beide sperren den Mutex. (Bei dir entsprechen die getter/setter also Funktion B). Wenn Funktion B die Invariante schon erhält, braucht A den Mutex nicht mehr zu sperren. Wenn sie es nicht tut, sollte sie nicht in der öffentlichen Schnittstelle sein. Wenn A manchmal über getter/setter auf interne Zustände zugreift, und manchmal direkt, hast du verschiedene Abstraktionsebenen darin. Wie du das Design schöner machen kannst, hat Torsten Robitzki schon geschrieben. > Welche Möglichkeiten gäbe es sonst noch? Du kannst die rekursiven Mutexes selbst programmieren, mit Hilfe von normalen Mutexes und einem Zähler. Falls du bei den normalen Mutexes rausfinden kannst, ob der Besitzer die gerade laufende Task ist. Sonst müsstest du dir in deinem rekursiven Mutex noch merken, welche Task der Besitzer ist. Dazu musst du nur irgendwie die Task-ID rausfinden können.
Hi Werner, für sowas kannst einen Watchdog nehmen, der schaltet die Liste mit Ampeln wieder flott,,,
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.