Bezpečnost závitu - Thread safety
![]() | Tento článek může vyžadovat vyčištění setkat se s Wikipedií standardy kvality. Specifický problém je: definice otevření je tautologická / kruhováLeden 2016) (Zjistěte, jak a kdy odstranit tuto zprávu šablony) ( |
Bezpečnost závitu je programování koncept použitelný pro vícevláknové kód. Kód bezpečný pro vlákna manipuluje pouze se sdílenými datovými strukturami způsobem, který zajišťuje, že se všechna vlákna chovají správně a splňují specifikace jejich návrhu bez nechtěné interakce. Existují různé strategie pro vytváření datových struktur bezpečných pro vlákna.[1][2]
Program může spustit kód v několika podprocesech současně ve sdíleném adresní prostor kde každé z těchto vláken má přístup k prakticky všem Paměť každého dalšího vlákna. Bezpečnost podprocesů je vlastnost, která umožňuje spuštění kódu v prostředí s více podprocesy opětovným vytvořením některých korespondencí mezi skutečným tokem řízení a textem programu pomocí synchronizace.
Úrovně bezpečnosti nití
Softwarové knihovny může poskytnout určité záruky bezpečnosti vláken. Například může být zaručeno, že souběžná čtení jsou bezpečná pro vlákna, ale souběžné zápisy nemusí být. To, zda je program využívající takovou knihovnu bezpečný pro vlákna, závisí na tom, zda knihovnu používá způsobem, který je v souladu s těmito zárukami.
Různí prodejci používají mírně odlišnou terminologii pro bezpečnost vláken:[3][4][5][6]
- Vlákno bezpečné: Implementace je zaručeně bez podmínky závodu při přístupu více vláken současně.
- Podmíněně bezpečné: Různá vlákna mohou přistupovat současně k různým objektům a přístup ke sdíleným datům je chráněn před rasovými podmínkami.
- Není bezpečné pro vlákna: K datovým strukturám by neměly být přistupovány současně různá vlákna.
Záruky bezpečnosti vláken obvykle zahrnují také konstrukční kroky k zabránění nebo omezení rizika různých forem zablokování, stejně jako optimalizace pro maximalizaci souběžného výkonu. Nelze však vždy poskytnout záruky bez zablokování, protože zablokování může být způsobeno zpětná volání a porušení architektonické vrstvení nezávislé na samotné knihovně.
Implementační přístupy
Níže probereme dvě třídy přístupů, jak se vyhnout podmínky závodu k dosažení bezpečnosti nití.
První třída přístupů se zaměřuje na vyhýbání se sdílenému stavu a zahrnuje:
- Znovuzavření
- Psaní kódu takovým způsobem, že může být částečně proveden vláknem, znovu proveden stejným vláknem nebo současně spuštěn jiným vláknem a stále správně dokončit původní provedení. To vyžaduje úsporu Stát informace v proměnných lokálních pro každé spuštění, obvykle na zásobníku, místo v statický nebo globální proměnné nebo jiný nelokální stav. Veškerý nelokální stav musí být přístupný prostřednictvím atomových operací a datové struktury musí být také znovu zadány.
- Místní úložiště vláken
- Proměnné jsou lokalizovány, takže každé vlákno má svou vlastní soukromou kopii. Tyto proměnné si zachovávají své hodnoty napříč podprogram a další hranice kódu a jsou bezpečné pro vlákna, protože jsou lokální pro každé vlákno, i když kód, který k nim přistupuje, může být spuštěn současně jiným vláknem.
- Neměnné objekty
- Stav objektu nelze po konstrukci změnit. To znamená, že jsou sdílena pouze data jen pro čtení, a že je dosaženo vlastní bezpečnosti podprocesů. Proměnlivé (nekonstantní) operace lze poté implementovat takovým způsobem, že místo úpravy existujících vytvoří nové objekty. Tento přístup je charakteristický pro Funkcionální programování a je také používán tětiva implementace v Javě, C # a Pythonu. (Vidět Neměnný objekt.)
Druhá třída přístupů souvisí se synchronizací a používá se v situacích, kdy nelze zabránit sdílenému stavu:
- Vzájemné vyloučení
- Přístup ke sdíleným datům je serializováno pomocí mechanismů, které zajistí, že na sdílená data bude číst nebo zapisovat kdykoli pouze jedno vlákno. Začlenění vzájemného vyloučení je třeba dobře promyslet, protože nesprávné použití může vést k vedlejším účinkům, jako je zablokování, živé zámky, a hladovění zdrojů.
- Atomové operace
- Ke sdíleným datům se přistupuje pomocí atomových operací, které nelze přerušit jinými vlákny. To obvykle vyžaduje použití speciálních jazyk stroje pokyny, které mohou být k dispozici v a běhová knihovna. Jelikož jsou operace atomické, sdílená data se vždy udržují v platném stavu, bez ohledu na to, jak k nim přistupují ostatní vlákna. Atomové operace tvoří základ mnoha mechanismů zamykání vláken a používají se k implementaci primitiv vzájemného vyloučení.
Příklady
V následujícím díle Jáva kód, klíčové slovo Java synchronizované dělá metodu bezpečnou pro vlákna:
třída Čelit { soukromé int i = 0; veřejnost synchronizované prázdnota vč() { i++; }}
V Programovací jazyk C., každé vlákno má svůj vlastní zásobník. Nicméně, a statická proměnná není veden na hromádce; všechna vlákna k němu sdílejí současný přístup. Pokud se při spuštění stejné funkce překrývá více vláken, je možné, že statická proměnná může být změněna jedním vláknem, zatímco jiné je uprostřed kontroly. To je obtížné diagnostikovat logická chyba, které se mohou většinu času správně zkompilovat a spustit, se nazývá a stav závodu. Jedním z běžných způsobů, jak tomu zabránit, je použít jinou sdílenou proměnnou jako „zámek“ nebo „mutex“ (z mutual napřshluk).
V následující části kódu C je funkce bezpečná pro vlákna, ale ne znovu zadaná:
# include int increment_counter (){ statický int čelit = 0; statický pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // povolit přírůstek pouze jednoho vlákna najednou pthread_mutex_lock(&mutex); ++čelit; // uloží hodnotu dříve, než ji ostatní vlákna zvýší int výsledek = čelit; pthread_mutex_unlock(&mutex); vrátit se výsledek;}
Ve výše uvedeném increment_counter
lze bez problémů volat různými vlákny, protože mutex se používá k synchronizaci veškerého přístupu ke sdílenému čelit
proměnná. Ale pokud je funkce použita v reentrantním obslužném programu přerušení a dojde k druhému přerušení, když je mutex uzamčen, druhá rutina bude navždy viset. Protože servis přerušení může deaktivovat další přerušení, mohl by utrpět celý systém.
Stejná funkce může být implementována tak, aby byla bezpečná pro vlákna i reentrantní pomocí bez zámku atomové v C ++ 11:
# include int increment_counter (){ statický std::atomový<int> čelit(0); // přírůstek je zaručeno provést atomicky int výsledek = ++čelit; vrátit se výsledek;}
Viz také
Reference
- ^ Kerrisk, Michael (2010). Programovací rozhraní Linux. Žádný lis na škrob. p. 655.
- ^ "Vícevláknový průvodce programováním". Oracle Corporation. Listopad 2010.
Procedura je bezpečná pro vlákna, když je procedura logicky správná, když je spuštěna současně několika vlákny.
- ^ "Reentrancy a bezpečnost vláken | Qt 5,6". Projekt Qt. Citováno 2016-04-20.
- ^ „ip :: tcp - 1.51.0“. Boost.org. Citováno 2013-10-16.
- ^ „Bezpečnostní klasifikace vláken API“. Publib.boulder.ibm.com. 09.06.1998. Citováno 2013-10-16.
- ^ „Úrovně bezpečnosti rozhraní MT - Multithreaded Programming Guide“. Docs.oracle.com. 2010-11-01. Citováno 2013-10-16.
externí odkazy
- Java Q&A Experts (20. dubna 1999). „Vlákno bezpečný design (20. 4. 1999)“. JavaWorld.com. Citováno 2012-01-22.
- TutorialsDesk (30. září 2014). „Výukový program pro synchronizaci a zabezpečení vláken s příklady v Javě“. TutorialsDesk.com. Citováno 2012-01-22.
- Venners, Bill (1. srpna 1998). "Design pro bezpečnost závitů". JavaWorld.com. Citováno 2012-01-22.
- Suess, Michael (15. října 2006). „Krátký průvodce zvládnutím bezpečnosti vláken“. Myslet paralelně. Citováno 2012-01-22.