Lugemis-kirjutamise lukkude kontseptsioon on lihtne, võimaldades mitmel lõimel samaaegselt lugemislukke omandada, kuid ainult üks lõim saab samaaegselt kirjutuslukke saada, seega nimetatakse seda ka jagatud eksklusiivseteks lukudeks. C#-s soovitatakse lugemise/kirjutamise funktsiooni lõpetamiseks kasutada ReaderWriterLockSlim klassi. Mõnel juhul on objekti lugemiste arv palju suurem kui muudatuste arv, ja kui see lukustatakse lihtsalt lukustamisega, mõjutab see lugemise efektiivsust. Kui kasutatakse lugemis-kirjutamise lukku, saavad mitmed lõimed objekti samaaegselt lugeda ning see blokeeritakse ainult siis, kui objekt on kirjutamislukuga hõivatud. Lihtsalt öeldes, kui lõim läheb lugemisrežiimi, võivad teised lõimed siiski lugemisrežiimi siseneda, eeldades, et lõim soovib sel hetkel kirjutamisrežiimi minna, siis tuleb see blokeerida. kuni lugemisrežiim lõpeb. Samamoodi, kui lõim läheb kirjutamisrežiimi, blokeeritakse teised lõimed, olenemata sellest, kas nad tahavad kirjutada või lugeda. Kirjutamis-/lugemisrežiimi sisenemiseks on kaks võimalust: EnterReadLock püüab siseneda kirjutamisrežiimi lukustusolekusse. TryEnterReadLock(Int32) üritab siseneda lugemisrežiimi lukustusolekusse, valides täisarvu timeout'i. EnterWriteLock püüab siseneda Write Mode Lock olekusse. TryEnterWriteLock (Int32) üritab siseneda kirjutamisrežiimi lukustusolekusse ning saab valida ajapiirangu aja. Kirjutamise/lugemise režiimist väljumiseks on kaks võimalust: ExitReadLock vähendab lugemisrežiimi rekursiivset arvu ja väljub lugemisrežiimist, kui tulemuseks on 0 (null). ExitWriteLock vähendab kirjutamismustri rekursiivset arvu ja väljub kirjutamisrežiimist, kui tulemuseks on 0 (null). Siin on, kuidas seda kasutada:
Näed, et lõim 3 ja lõim 4 võivad samaaegselt lugemisrežiimi minna, samas kui lõim 5 võib minna kirjutamisrežiimi 5 sekundi pärast (see tähendab, et lõimed 3 ja 4 väljuvad lugemislukust). Muuda ülaltoodud koodi, avades esmalt 2 lõime kirjutamisrežiimis ja seejärel lõimed lugemisrežiimis, kood on järgmine:
Tulemused on järgmised:
Nagu näha, lähevad lõim 3 ja lõim 4 mõlemad kirjutamisrežiimi, kuid lõim 3 hõivab kirjutamisluku esimesena, nii et lõim 4 peab ootama 10 sekundit, enne kui siseneb. Lõimed 5 ja 6 peavad olema lugemislukku, nii et oota, kuni lõim 4 kirjutamislukust väljub, enne kui jätkad. TryEnterReadLock ja TryEnterWriteLock võivad seada timeout'i, selle lause käivitamisel blokeeritakse lõim siin, kui lukustus on sel hetkel hõivatud, siis tagastatakse true, kui timeout'i aeg pole veel lukku hõivanud, siis tagastatakse false, loobutakse lukustuse hõivamisest ja jätkatakse järgmise koodi otse täitmist. EnterUpgradeableReadLock ReaderWriterLockSlim klass pakub uuendatavat lugemisrežiimi, mis erineb lugemisrežiimist selle poolest, et seda saab uuendada kirjutamisrežiimile, kutsudes EnterWriteLock või TryEnterWriteLock meetodeid. Sest korraga saab uuendatavas režiimis olla ainult üks lõim. Lõim, mis läheb uuendatavasse režiimi, ei mõjuta lugemisrežiimis lõime, st kui lõim läheb uuendatavasse režiimi, võib lugemisrežiimi samaaegselt siseneda ükskõik milline arv lõime ilma blokeerimiseta. Kui mitu lõime ootavad juba kirjutamislukku, blokeerib EnterUpgradeableReadLock käivitamine kuni need lõimed aeguvad või kirjutamislukust väljuvad. Järgmine kood näitab, kuidas uuendada kirjutamislukku uuendatavas lugemisrežiimis.
Lugemise/kirjutamise lukustuste mõju jõudlusele on ilmne. Järgmine testkood:
Ülaltoodud kood simuleerib 500 ülesande töötlemist, millest igaüks hõivab ühe lõimepooli lõime, millest 20 on kirjutamislõimed ja 480 lugemislõime simuleeritud. Andmete lugemiseks kulub 10 ms ja lukustusmeetodi ja ReaderWriterLockSlim meetodi testimiseks 100 ms. ReaderWriterLockSlim'i puhul saab teha hinnangu, eeldades, et 480 lõime loetakse samaaegselt, siis tarbib see 10ms, 20 kirjutamistoimingut võtab 2000ms, seega kulub aeg 2010ms, ja tavalise lukustusmeetodi puhul, kuna need on kõik eksklusiivsed, võtab 480 lugemisoperatsiooni 4800ms + 20 kirjutamisoperatsiooni 2000ms = 6800ms. Tulemused näitasid märgatavat jõudluse paranemist.
|