Luku- ja kirjoituslukkojen käsite on yksinkertainen: useat säikeet voivat saada lukulukkoja samanaikaisesti, mutta vain yksi säie saa kirjoituslukot samanaikaisesti, joten sitä kutsutaan myös jaetuiksi lukituksiksi. C#:ssa suositellaan käyttämään ReaderWriterLockSlim-luokkaa luku-/kirjoitus-toiminnon suorittamiseen. Joissain tapauksissa objektille lukujen määrä on paljon suurempi kuin muutosten määrä, ja jos se lukitaan pelkästään lukitsemalla, se vaikuttaa lukemisen tehokkuuteen. Jos käytetään luku-kirjoituslukkoa, useat säikeet voivat lukea objektia samanaikaisesti, ja se estetään vain, kun olio on kirjoituslukon käytössä. Yksinkertaisesti sanottuna, kun säie siirtyy lukutilaan, muut säikeet voivat silti siirtyä lukutilaan, olettaen että säie haluaa kirjoittaa tällä hetkellä, jolloin säie täytyy estää. kunnes lukutila poistuu. Samoin, jos säie menee kirjoitustilaan, muut säikeet estetään, halusivatpa ne kirjoittaa tai lukea. Kirjoitus-/lukutilaan voi siirtyä kahdella tavalla: EnterReadLock yrittää siirtyä kirjoitustilan lukitustilaan. TryEnterReadLock(Int32) yrittää siirtyä lukutilan lukitustilaan, jossa on mahdollisuus valita kokonaislukuaikakatkaisu. EnterWriteLock yrittää siirtyä Write Mode Lock -tilaan. TryEnterWriteLock(Int32) yrittää siirtyä kirjoitustilan lukitustilaan, ja aikakatkaisuaika voidaan valita. Kirjoitus/lukutilasta voi poistua kahdella tavalla: ExitReadLock vähentää lukutilan rekursiivista määrää ja poistuu lukutilasta, kun tuloksena oleva lukumäärä on 0 (nolla). ExitWriteLock vähentää kirjoituskuvion rekursiivista määrää ja poistuu kirjoitustilasta, kun tuloksena oleva lukumäärä on 0 (nolla). Näin sitä käytetään:
Näet, että säie 3 ja säide 4 voivat siirtyä lukutilaan samanaikaisesti, kun taas säie 5 voi siirtyä kirjoitustilaan 5 sekunnin jälkeen (eli kun säikeet 3 ja 4 poistuvat lukulukosta). Muokkaa yllä olevaa koodia, avaa ensin 2 säikettä kirjoitustilassa ja sitten avaa säikeet lukutilassa, koodi on seuraava:
Tulokset ovat seuraavat:
Kuten näet, säie 3 ja säie 4 siirtyvät kirjoitustilaan, mutta säie 3 vie kirjoituslukon ensin, joten säie 4 joutuu odottamaan 10 sekuntia ennen kuin menee sisään. Säikeiden 5 ja 6 täytyy olla lukulukossa, joten odota, että säide 4 poistuu kirjoituslukosta ennen kuin jatkat. TryEnterReadLock ja TryEnterWriteLock voivat asettaa aikakatkaisun, kun tämä lause etenee, säie estetään tässä, jos lukko voidaan varata tällä hetkellä, palauttaa true, jos aikakatkaisuaika ei ole vielä täyttänyt lukkoa, palautetaan false, luovutaan lukon miehityksestä ja jatkaa seuraavan koodin suorittamista suoraan. EnterUpgradeableReadLock ReaderWriterLockSlim-luokka tarjoaa päivitettävän lukutilan, joka eroaa lukutilasta siinä, että sen voi myös päivittää kirjoitustilaan kutsumalla EnterWriteLock- tai TryEnterWriteLock-metodeja. Koska vain yksi säie voi olla päivitettävässä tilassa kerrallaan. Säie, joka siirtyy päivitettävään tilaan, ei vaikuta lukutilassa olevaan säikeeseen, eli kun säie siirtyy päivitettäväksi, lukutilaan voi mennä samanaikaisesti lukutilaan ilman estettä. Jos useat säikeet odottavat jo kirjoituslukon saamista, EnterUpgradeableReadLockin ajaminen estää, kunnes säikeet sulkeutuvat tai poistuvat kirjoituslukosta. Seuraava koodi näyttää, miten päivitetään kirjoituslukkoon päivitettävässä lukutilassa.
Luku-/kirjoituslukkojen vaikutus suorituskykyyn on ilmeinen. Seuraava testikoodi:
Yllä oleva koodi simuloi 500 tehtävän toimintaa, joista kukin vie säiepoolin säikeen, joista 20 on kirjoitussäikeitä ja 480 lukusäikeitä. Datan lukemiseen kuluu 10 ms ja lukitusmenetelmän ja ReaderWriterLockSlim-menetelmän testaamiseen 100 ms kirjoittamiseen. Arvio voidaan tehdä ReaderWriterLockSlimille, olettaen, että 480 säikettä luetaan samanaikaisesti, jolloin se kuluttaa 10 ms, 20 kirjoitusoperaatiota vie 2000 ms, jolloin kulutettu aika on 2010 ms, ja tavalliselle lukitusmenetelmälle, koska ne ovat kaikki eksklusiivisia, 480 lukutoimintoa vie 4800ms + 20 kirjoitusoperaatiota 2000ms = 6800ms. Tulokset osoittivat huomattavaa suorituskyvyn parannusta.
|