Zadávání poznámek o chování při zamykání
Aby nedocházelo k chybám souběžnosti v programu s více vlákny, vždy postupujte podle příslušného pravidla uzamykání a použijte poznámky SAL.
Chyby souběžnosti jsou obvykle odlaďujeelné k reprodukování, diagnostice a ladění, protože nejsou deterministické. Rozhodnutí o proplutí vlákna je obtížné, a Pokud navrhujete tělo kódu, který má více než několik vláken, je nepraktické. Proto je dobrým zvykem sledovat v aplikacích s více vlákny blokovací obor. Například nastavování pořadí zámků a získání více zámků pomáhá zabránit zablokování a získání správného zámku ochrany před přístupem ke sdílenému prostředku pomáhá zabránit konfliktům časování.
Zdánlivě jednoduchá pravidla zamykání ale můžou být v praxi překvapivěá. Základní omezení dnešních programovacích jazyků a kompilátorů je, že nepodporují přímo specifikace a analýzu požadavků na souběžnost. Programátoři musí spoléhat na neformální komentáře kódu, aby vyjádřili své záměry o používání zámků.
Anotace SAL pro souběžnost jsou navržené tak, aby vám pomohly určit uzamčené vedlejší účinky, odpovědnost za uzamykání, strážci dat, hierarchii pořadí zámků a další očekávané chování při zamykání. V případě explicitních implicitních pravidel jsou anotace souběžnosti SAL zajištěny konzistentní způsob, jak váš kód používá pravidla uzamykání. Anotace souběžnosti také zlepšují schopnost nástrojů pro analýzu kódu najít konflikty časování, zablokování, neshodné operace synchronizace a další drobné chyby souběžnosti.
Obecné pokyny
Pomocí poznámek můžete uvést smlouvy, které jsou vyvolány definicemi funkcí mezi implementacemi (volané) a klienty (volajícími) a expresními variantami a dalšími vlastnostmi programu, které mohou dále vylepšit analýzu.
SAL podporuje mnoho různých druhů uzamykání primitiv – například důležité oddíly, mutexy, zámky a další objekty prostředků. Mnoho anotací souběžnosti přijímá výraz zámku jako parametr. Podle konvence je zámek označen výrazem cesty podkladového objektu zámku.
Některá pravidla vlastnictví vláken, která si zapamatujte:
Zámky jsou nespočítatelné zámky, které mají jasné vlastnictví vlákna.
Odblokování a kritické oddíly jsou započítány zámky, které mají jasné vlastnictví vlákna.
Semafory a události jsou započítány zámky, které nemají jasné vlastnictví vlákna.
Uzamčené poznámky
V následující tabulce jsou uvedeny anotace zamykání.
| Poznámka | Popis |
|---|---|
_Acquires_exclusive_lock_(expr) |
Přidá do funkce poznámku a určí, že ve stavu post funkce se zvýší o jeden a exkluzivní počet zámků objektu zámku, který je pojmenován pomocí expr . |
_Acquires_lock_(expr) |
Přidá do funkce poznámku a určí, že ve stavu post funkce se zvýší o jeden počet zámků objektu zámku, který je pojmenován pomocí expr . |
_Acquires_nonreentrant_lock_(expr) |
Zámek, který je pojmenován pomocí, expr získá. Pokud je zámek již uložen, je hlášena chyba. |
_Acquires_shared_lock_(expr) |
Přidá do funkce poznámku a určí, že ve stavu post funkce přiroste o jeden sdílený počet zámků objektu zámku, který je pojmenován pomocí expr . |
_Create_lock_level_(name) |
Příkaz, který deklaruje symbol jako name Úroveň zámku, aby mohl být použit v poznámkách _Has_Lock_level_ a _Lock_level_order_ . |
_Has_lock_kind_(kind) |
Připíše libovolný objekt k upřesnění informací o typu objektu prostředku. Někdy se používá společný typ pro různé druhy prostředků a přetížený typ není dostačující pro odlišení sémantických požadavků mezi různými prostředky. Tady je seznam předem definovaných kind parametrů:_Lock_kind_mutex_ID typu zámku pro mutexy _Lock_kind_event_ID typu zámku pro události _Lock_kind_semaphore_ID typu zámku pro semafory. _Lock_kind_spin_lock_ID typu zámku pro zámky _Lock_kind_critical_section_ID typu zámku pro kritické oddíly |
_Has_lock_level_(name) |
Přikáže uzamčenému objektu a poskytne mu úroveň zámku name . |
_Lock_level_order_(name1, name2) |
Příkaz, který poskytuje řazení zámku mezi name1 a name2 . Zámky, které mají úroveň, name1 musí být získány před zámky, které mají úroveň name2 . |
_Post_same_lock_(expr1, expr2) |
Označí funkci jako poznámku a označuje, že ve stavu post jsou dvě zámky expr1 a expr2 , se považují za, jako by se jednalo o stejný objekt zámku. |
_Releases_exclusive_lock_(expr) |
Doplní funkci a určí, že ve stavu post je funkce snížena o jeden a exkluzivní počet zámků objektu zámku, který je pojmenován pomocí expr . |
_Releases_lock_(expr) |
Doplní funkci a určí, že ve stavu post je funkce snížena o jeden počet zámků objektu zámku, který je pojmenován pomocí expr . |
_Releases_nonreentrant_lock_(expr) |
Zámek s názvem by expr byl vydán. Pokud zámek momentálně není držen, je hlášena chyba. |
_Releases_shared_lock_(expr) |
Doplní funkci a určí, že ve stavu post je funkce snížena o jeden sdílený počet zámků objektu zámku, který je pojmenován pomocí expr . |
_Requires_lock_held_(expr) |
Doplní funkci a určí, že v předběžném stavu je počet zámků objektu, který je pojmenován pomocí, expr aspoň jeden. |
_Requires_lock_not_held_(expr) |
Doplní funkci a určí, že v předběžném stavu je počet zámků objektu, který je pojmenován na expr hodnotu nula. |
_Requires_no_locks_held_ |
Označí funkci jako poznámku a indikuje, že počet zámků všech zámků, které jsou pro tuto kontrolu známy, je nula. |
_Requires_shared_lock_held_(expr) |
Označí funkci jako poznámku a označuje, že v předběžné verzi se sdíleným počtem zámků objektu, který je pojmenován, expr nachází alespoň jeden. |
_Requires_exclusive_lock_held_(expr) |
Doplní funkci a určí, že v předběžné verzi objektu, který je pojmenován pomocí, expr je alespoň jeden. |
Vnitřní prvky SAL pro neexponované uzamčené objekty
Některé objekty zámku nejsou zpřístupněny implementací přidružených funkcí zamykání. V následující tabulce jsou uvedeny vnitřní proměnné SAL, které umožňují poznámky k funkcím, které pracují s těmito nevystavenými objekty zámku.
| Poznámka | Popis |
|---|---|
_Global_cancel_spin_lock_ |
Popisuje uzamčení číselníku zrušit. |
_Global_critical_region_ |
Popisuje kritickou oblast. |
_Global_interlock_ |
Popisuje propojené operace. |
_Global_priority_region_ |
Popisuje oblast priority. |
Sdílené poznámky k přístupu ke sdíleným datům
V následující tabulce jsou uvedeny poznámky pro přístup ke sdíleným datům.
| Poznámka | Popis |
|---|---|
_Guarded_by_(expr) |
Označí proměnnou jako poznámku a určí, že pokaždé, když je k proměnné přistupovat, je počet zámků objektu zámku, který je pojmenován pomocí, expr aspoň jeden. |
_Interlocked_ |
Označí proměnnou jako poznámku a je ekvivalentní _Guarded_by_(_Global_interlock_) . |
_Interlocked_operand_ |
Parametr funkce s poznámkou je cílovým operandem jedné z různých vzájemně propojených funkcí. Tyto operandy musí mít konkrétní další vlastnosti. |
_Write_guarded_by_(expr) |
Označí proměnnou jako poznámku a určí, že pokaždé, když je upravena proměnná, je počet zámků objektu zámku, který je pojmenován pomocí, expr aspoň jeden. |
Poznámky Smart Lock a RAII
Inteligentní Zámky obvykle zabalí Nativní zámky a spravují jejich životnost. V následující tabulce jsou uvedeny poznámky, které lze použít s inteligentními zámky a vzory kódování RAII s podporou move sémantiky.
| Poznámka | Popis |
|---|---|
_Analysis_assume_smart_lock_acquired_ |
Dává analyzátoru pokyn, aby předpokládal, že byl získán inteligentní zámek. Tato poznámka očekává jako svůj parametr typ zámku odkazu. |
_Analysis_assume_smart_lock_released_ |
Dává analyzátoru pokyn, aby předpokládal, že byl vydán inteligentní zámek. Tato poznámka očekává jako svůj parametr typ zámku odkazu. |
_Moves_lock_(target, source) |
Popisuje move constructor operaci, která přenáší stav zámku z source objektu na target . targetJe považován za nově vytvořený objekt, takže všechny stavy, které byly před, budou ztraceny a nahrazeny source stavem. sourceDojde také k resetování na čistý stav bez počtu zámků nebo cíle aliasu, ale aliasy ukazující na něj zůstanou beze změny. |
_Replaces_lock_(target, source) |
Popisuje move assignment operator sémantiku, kde je uvolněn cílový zámek před přenosem stavu ze zdroje. To je možné považovat za kombinaci _Moves_lock_(target, source) předchází _Releases_lock_(target) . |
_Swaps_locks_(left, right) |
Popisuje standardní swap chování, které předpokládá, že objekty left a right vyměňují jejich stav. Výměna stavu zahrnuje počet zámků a cíl aliasů, pokud je k dispozici. Aliasy, které odkazují left na right objekty a, zůstávají beze změny. |
_Detaches_lock_(detached, lock) |
Popisuje scénář, ve kterém typ zámku obálky umožňuje zrušení bylo s jeho obsaženým prostředkem. To se podobá tomu, jak std::unique_ptr funguje s vnitřním ukazatelem: umožňuje programátorům extrahovat ukazatel a opustit jeho kontejner inteligentního ukazatele v čistém stavu. Podobná logika je podporována nástrojem std::unique_lock a může být implementována ve vlastních obálkách zámku. Odpojený zámek si zachová svůj stav (počet zámků a cíl aliasů), zatímco obálka je resetována tak, aby obsahovala nulový počet zámků a žádný cíl pro vytváření aliasů a současně si zachovává vlastní aliasy. Neexistují žádné operace na počtu zámků (uvolnění a získání). Tato poznámka se chová přesně s _Moves_lock_ tím rozdílem, že odpojený argument by měl být return spíše než this . |