Moja dva centa na SpinLocku u .Netu

Zamislite situaciju u kojoj nit pokušava dobiti pristup zajedničkom resursu, ali je resurs već zaključan, tako da nit mora pričekati dok se zaključavanje ne oslobodi. Evo gdje sinhronizacija niti dolazi u obzir. Sinkronizacija niti koristi se kako bi se spriječilo da više niti istovremeno pristupa zajedničkom resursu. Microsoft .Net Framework pruža podršku za niz primitiva za sinkronizaciju koji se mogu koristiti za kontrolu ponašanja niti i izbjegavanje uvjeta utrke. Mutex i Spinlock dva su popularna mehanizma za sinkronizaciju koji se koriste za sinkronizaciju pristupa zajedničkom resursu.

SpinLock je alternativa blokiranju sinkronizacije. SpinLock (poznat i kao "Zauzeto čekanje") je mehanizam koji se može koristiti za stvaranje niti koja pokušava dobiti zaključavanje u petlji dok ne dobije pristup resursu. Imajte na umu da SpinLock može raditi brže u usporedbi s Mutexom jer je prebacivanje konteksta smanjeno. Međutim, trebali biste koristiti SpinLocks samo ako bi kritični odjeljak trebao obaviti minimalnu količinu posla, tj. SpinLock se drži vrlo kratko vrijeme. U simetričnim višeprocesorskim sustavima obično se preferira SpinLocks za stalno ispitivanje dostupnosti resursa umjesto kontekstnih prekidača.

Što je SpinLock i zašto je potreban?

SpinLock izvodi zauzeto čekanje i može ponuditi bolje performanse kada se koristi u višejezgrenim sustavima, posebno kada je jeftino čekati u petlji i objediniti resurs, a ne blokirati ga. To je osobito korisno kada su vremena zadržavanja zaključavanja kratka. Drugim riječima, SpinLock možete iskoristiti u višejezgrenim sustavima kako biste smanjili općenite troškove koji su uključeni u prebacivanje konteksta ako je vrijeme provedeno unutar kritičnog odjeljka malo. Kritični odjeljak može se definirati kao struktura podataka ili resurs koji dijeli više niti, ali jedna i samo jedna nit može mu pristupiti u bilo kojem trenutku.

Treba imati na umu da bi držanje SpinLocka duže vrijeme jednostavno bilo gubljenje resursa sustava i štetno za izvedbu aplikacije. U osnovi, ako očekujete da će blokiranje biti značajnog trajanja, SpinLock se nikada ne smije koristiti - koristite SpinLock samo kada je vrijeme zadržavanja brave razmjerno malog trajanja.

SpinLock se obično koristi kada se radi s prekidima za obavljanje zauzetog čekanja unutar petlje dok se resurs ne učini dostupnim. SpinLock ne uzrokuje sprečavanje niti, već se nastavlja vrtjeti dok se ne oslobodi zaključavanje resursa.

Programiranje SpinLocka u .Net

Imajte na umu da je SpinLock definiran kao struktura u .Netu, tj. Definiran je kao vrsta vrijednosti iz razloga izvedbe. Stoga, ako prolazite oko instance SpinLock, trebali biste je proslijediti referencom, a ne vrijednošću. U ovom ćemo odjeljku istražiti kako možemo programirati SpinLock u .Netu. Da biste implementirali SpinLock u .Net, trebali biste iskoristiti klasu SpinLock dostupnu u prostoru imena System.Threading.

Sljedeći popis kodova pokazuje kako možete koristiti SpinLock u .Netu.

SpinLock spinLock = new SpinLock (true);

bool isLocked = false;

try

{

spinLock.Enter (ref isLocked);

// Write your usual code here

}

finally

{

if (isLocked)

   spinLock.Exit();

}

SpinWait

Imajte na umu da je poput SpinLock-a i SpinWait struktura, a ne klasa. Slično SpinLocku, SpinWait možete koristiti za pisanje sinkronizacijskog koda bez zaključavanja koji se može "vrtjeti", a ne blokirati. SpinWait se može koristiti za smanjenje potrošnje resursa izvođenjem intenzivnog CPU okretanja za 10 iteracija nakon čega će dati kontrolu pozivanjem Thread.Yield i Thread.Sleep. Drugim riječima, SpinWait se može koristiti za ograničavanje CPU-intenzivnog okretanja na fiksni broj iteracija. MSDN navodi: "System.Threading.SpinWait je lagana vrsta sinkronizacije koju možete koristiti u scenarijima niske razine kako biste izbjegli skupe preklopnike konteksta i prijelaze jezgre koji su potrebni za događaje jezgre."

Da biste koristili SpinWait u svom kodu, možete upotrijebiti statičku metodu SpinUntil () strukture SpinWait ili iskoristiti njenu nestatičku metodu SpinOnce (). Sljedeći isječak koda ilustrira kako se SpinWait može koristiti.

SpinWait spinWait = new SpinWait();

bool shouldSpin;

while (!shouldSpin)

{

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

}