Verschillen tussen voorwaardelijke variabelen, mutexen en vergrendelingen

Bijvoorbeeld de c++0x-interfaces

Ik vind het moeilijk om te bepalen wanneer ik welke van deze dingen moet gebruiken (cv, mutex en slot).
Kan iemand een bron uitleggen of naar een bron verwijzen?

Bij voorbaat dank.


Antwoord 1, autoriteit 100%

Op de pagina waarnaar u verwijst, is “mutex” de eigenlijke synchronisatieprimitief op laag niveau. Je kunt een mutex nemen en deze vervolgens loslaten, en slechts één thread kan deze tegelijkertijd aannemen (vandaar dat het een synchroniserende primitief is). Een recursieve mutex is er een die meerdere keren door dezelfde dezelfdethread kan worden genomen, en die vervolgens zo vaak door dezelfde thread moet worden vrijgegeven voordat anderen hem kunnen nemen.

Een “lock” hier is slechts een C++-wrapperklasse die een mutex in zijn constructor neemt en deze bij de destructor vrijgeeft. Het is handig om synchronisatie voor C++-scopes tot stand te brengen.

Een conditievariabele is een meer geavanceerde/hogere vorm van primitieve synchronisatie die een vergrendeling combineert met een “signalerings”-mechanisme. Het wordt gebruikt wanneer threads moeten wachten tot een bron beschikbaar komt. Een thread kan “wachten” op een CV en dan kan de bronproducent de variabele “signaleren”, in welk geval de threads die op de CV wachten een melding krijgen en de uitvoering kunnen voortzetten. Een mutex wordt gecombineerd met CV om de race-conditie te vermijden waarbij een thread op een CV begint te wachten terwijl een andere thread het wil signaleren; dan is het niet te controleren of het signaal wordt afgeleverd of verloren gaat.


Antwoord 2, autoriteit 6%

Ik ben niet zo bekend met C++0x, dus neem dit antwoord met een korreltje zout.

re: Mutex vs. locks: uit de documentatie die je hebt gepost, lijkt het alsof een mutexeen object is dat een OS mutex vertegenwoordigt, terwijl een lockeen object is dat heeft een mutex om het RAII-patroonte vergemakkelijken.

Voorwaardevariabelen zijn een handig mechanisme om een ​​blokkerings-/signaleringsmechanisme (signaal+wacht) te associëren met een wederzijds uitsluitingsmechanisme, maar ze ontkoppeld te houden in het besturingssysteem, zodat u als systeemprogrammeur de associatie tussen condvar en mutex kunt kiezen. (handig voor het omgaan met meerdere sets gelijktijdig geopende objecten) Rob Krten heeft een aantal goede uitleg over condvarsin een van de online hoofdstukken van zijn boek over QNX.

Voor zover algemene referenties: Dit boek(nog niet uit) ziet er interessant uit.


Antwoord 3, autoriteit 4%

Deze vraag is beantwoord. Ik voeg dit gewoon toe dat kan helpen om te beslissen WANNEER deze synchronisatieprimitieven moeten worden gebruikt.

De mutex wordt eenvoudigweg gebruikt om wederzijdse toegang tot een gedeelde bron in het kritieke gedeelte van meerdere threads te garanderen. Geluk is een algemene term, maar een binaire mutex kan als slot worden gebruikt. In moderne C++ gebruiken we lock_guard en soortgelijke objecten om RAII te gebruiken om het mutex-gebruik te vereenvoudigen en veilig te maken. De voorwaardelijke variabele is een andere primitieve die vaak wordt gecombineerd met een mutex om iets bekend te maken als een monitor.

Ik vind het moeilijk om te bepalen wanneer ik welke van deze dingen moet gebruiken
(cv, mutex en slot). Kan iemand a.u.b. uitleggen of verwijzen naar een
bron?

Gebruik een mutex om wederzijds exclusieve toegang tot iets te garanderen. Het is de standaardoplossing voor een breed scala aan gelijktijdigheidsproblemen. Gebruik lock_guard als je een scope in C++ hebt die je wilt bewaken met een mutex. De mutex wordt afgehandeld door de lock_guard. U maakt gewoon een lock_guard in de scope en initialiseert deze met een mutex en dan doet C++ de rest voor u. De mutex wordt vrijgegeven wanneer het bereik van de stapel wordt verwijderd, om welke reden dan ook, inclusief het gooien van een uitzondering of het terugkeren van een functie. Het is het idee achter RAIIen de lock_guard is een andere resource-handler.

Sommige gelijktijdigheidsproblemen zijn niet eenvoudig op te lossen door alleen een mutex te gebruiken, of een eenvoudige oplossing kan leiden tot complexiteit of inefficiëntie. Het produced-consumer-probleemis er bijvoorbeeld een van. Als we een consumententhread willen implementeren die items leest uit een buffer die wordt gedeeld met een producent, moeten we de buffer beschermen met een mutex, maar zonder een voorwaardelijke variabele te gebruiken, moeten we de mutex vergrendelen, de buffer controleren en een item lezen als het niet leeg is , ontgrendel het en wacht een tijdje, vergrendel het opnieuw en ga verder. Het is zonde van de tijd als de buffer vaak leeg is (druk wachten) en er ook veel wordt vergrendeld en ontgrendeld en slaapt.

De oplossing die we nodig hebben voor het probleem producent-consument moet eenvoudiger en efficiënter zijn. Een monitor (een mutex + een conditionele variabele) helpt ons hierbij. We hebben nog steeds een mutex nodig om wederzijds exclusieve toegang te garanderen, maar een voorwaardelijke variabele laat ons slapen en wachten op een bepaalde voorwaarde. De voorwaarde hier is dat de producent een item aan de buffer toevoegt. De producententhread meldt de consumententhread dat er een item in de buffer is en de consument wordt wakker en krijgt het item. Simpelweg, de producent vergrendelt de mutex, stopt iets in de buffer, informeert de consument. De consument vergrendelt de mutex, slaapt terwijl hij wacht op een voorwaarde, wordt wakker als er iets in de buffer zit en haalt het item uit de buffer. Het is een eenvoudigere en efficiëntere oplossing.

De volgende keer dat je met een gelijktijdigheidsprobleem wordt geconfronteerd, denk dan zo: als je wederzijds exclusieve toegang tot iets nodig hebt, gebruik dan een mutex. Gebruik lock_guard als u veiliger en eenvoudiger wilt zijn. Als het probleem een ​​aanwijzing heeft van wachten op een voorwaarde die in een andere thread moet voorkomen, hebt u MOGELIJK een voorwaardelijke variabele nodig.

Als algemene vuistregel: analyseer eerst uw probleem en probeer een beroemd gelijktijdigheidsprobleem te vinden dat vergelijkbaar is met het uwe (zie bijvoorbeeld het gedeelte over klassieke synchronisatieproblemen in deze pagina). Lees over de voorgestelde oplossingen voor de bekende oplossing om de beste te bereiken. Mogelijk heb je wat aanpassingen nodig.

Other episodes