Programování

Moje dva centy na SpinLock v .Net

Představte si situaci, ve které se vlákno pokouší získat přístup ke sdílenému prostředku, ale prostředek je již uzamčen, takže vlákno musí počkat, dokud se zámek neuvolní. Zde přichází na řadu synchronizace vláken. Synchronizace vláken se používá k zabránění více vláknům v současném přístupu ke sdílenému prostředku. Microsoft .Net Framework poskytuje podporu pro řadu synchronizačních primitiv, které lze použít pro řízení chování podprocesů a vyhnutí se podmínkám závodu. Mutex a Spinlock jsou dva populární synchronizační mechanismy používané k synchronizaci přístupu ke sdílenému prostředku.

SpinLock je alternativou k blokování synchronizace. SpinLock (také známý jako „Busy Waiting“) je mechanismus, který lze použít k vytvoření vlákna, které se pokouší získat zámek, čekat ve smyčce, dokud nebude moci získat přístup k prostředku. Všimněte si, že SpinLock může ve srovnání s Mutexem fungovat rychleji, protože přepínání kontextu je omezené. Měli byste však používat SpinLocks pouze v případě, že kritická část má provádět minimální množství práce, tj. SpinLock je držen po velmi krátkou dobu. SpinLocks jsou obvykle preferovány v symetrických víceprocesorových systémech pro neustálé dotazování na dostupnost prostředku místo kontextových přepínačů.

Co je SpinLock a proč je potřeba?

SpinLock provádí rušné čekání a může nabídnout lepší výkon při použití ve vícejádrových systémech, zvláště když je levné čekat ve smyčce a sdružovat prostředek, spíše než blokovat. To je obzvláště užitečné, pokud jsou doby držení zámku krátké. Jinými slovy můžete využít výhod SpinLock ve vícejádrových systémech ke snížení režie spojené s přepínáním kontextu, pokud je čas strávený uvnitř kritické sekce malý. Kritická část může být definována jako datová struktura nebo prostředek, který je sdílen více vlákny, ale jedno a pouze jedno vlákno k němu může mít přístup v daném okamžiku.

Je třeba poznamenat, že delší držení SpinLocku by bylo prostě plýtváním prostředky systému a škodlivými pro výkon aplikace. V zásadě, pokud očekáváte, že blokování bude mít značné trvání, SpinLock by se nikdy neměl používat - použijte SpinLock pouze v případě, že doba zadržení zámku bude přiměřeně malá.

SpinLock se obvykle používají při práci s přerušeními k provádění rušného čekání uvnitř smyčky, dokud není prostředek k dispozici. SpinLock nezpůsobí, že vlákno bude preempted, spíše se točí, dokud se neuvolní zámek na prostředku.

Programování SpinLock v .Net

Všimněte si, že SpinLock je definován jako struktura v .Net, tj. Je z důvodů výkonu definován jako typ hodnoty. Pokud tedy předáváte instanci SpinLock, měli byste ji předat odkazem a ne hodnotou. V této části prozkoumáme, jak můžeme programovat SpinLock v .Net. Chcete-li implementovat SpinLock v .Net, budete muset využít třídu SpinLock dostupnou v oboru názvů System.Threading.

Následující výpis kódu ukazuje, jak můžete použít SpinLock v .Net.

SpinLock spinLock = nový SpinLock (true);

bool isLocked = false;

Snaž se

{

spinLock.Enter (ref isLocked);

// Sem napište obvyklý kód

}

Konečně

{

if (isLocked)

spinLock.Exit ();

}

SpinWait

Všimněte si, že stejně jako SpinLock, SpinWait je také struktura a ne třída. Podobně jako SpinLock, můžete použít SpinWait k zápisu synchronizačního kódu bez zámku, který se může spíše „točit“ než blokovat. SpinWait lze použít ke snížení spotřeby prostředků provedením intenzivního otáčení procesoru po 10 iteračních příspěvcích, které získá kontrolu voláním Thread.Yield a Thread.Sleep. Jinými slovy lze SpinWait použít k omezení spřádání náročného na CPU na pevný počet iterací. MSDN uvádí: "System.Threading.SpinWait je lehký typ synchronizace, který můžete použít v nízkoúrovňových scénářích, abyste se vyhnuli nákladným kontextovým přepínačům a přechodům jádra, které jsou vyžadovány pro události jádra."

Chcete-li ve svém kódu použít SpinWait, můžete buď využít statickou metodu SpinUntil () struktury SpinWait, nebo využít její statickou metodu SpinOnce (). Následující fragment kódu ukazuje, jak lze použít SpinWait.

SpinWait spinWait = nový SpinWait ();

bool shouldSpin;

while (! shouldSpin)

{

Thread.MemoryBarrier (); spinWait.SpinOnce ();

}