Oletame, et on klass, mis sisaldab avalikku intellekti loendurivälja, millele pääseb ligi mitme lõime kaudu, ja see arv ainult suureneb või väheneb.
Selle välja lisamisel, millist järgmistest skeemidest tuleks kasutada ja miks?
- lukusta(this.locker) this.counter++;
- Interlocked.Increment (viide sellele vastavale loendurile);
- Muuda counter access modifikaator public volatile'iks
Halvim (ükski neist tegelikult ei tööta)
Muuda counter access modifikaator public volatile'iks
See lähenemine ei ole tegelikult üldse turvaline ning volatiilsuse põhjus seisneb selles, et mitmed lõimed, mis töötavad mitmel protsessoril, puhverdavad andmeid ja korraldavad täidetud käske ümber.
Kui see on mittevolatiilne, peab CPU B ootama, et näha suurenenud väärtust, mis võib põhjustada probleeme.
Kui see on volatiilne, tagab see, et mõlemad protsessorid näevad sama väärtust samaaegselt. Kuid see ei väldi ristlõikelisi lugemis- ja kirjutamistoiminguid.
Väärtuse lisamine muutujale võtab tegelikult kolm sammu
1. Lugemine, 2. Lisa 3. Kirjuta
Oletame, et lõim A loeb loenduri väärtuse kui 1 ega ole valmis suurendama, siis lõim B loeb samuti loenduri väärtuse kui 1 ning mõlemad lõimed hakkavad tegema inkrementaalseid ja kirjutamisoperatsioone. Lõpploenduri väärtus on 2. See ei ole õige, mõlemad lõimed on teinud suurendamise operatsiooni ja õige tulemus peaks olema 3. Seega on selle nimetamine muutlikuks lihtsalt ohtlik.
See on parem
lukusta(this.locker) this.counter++;
Nii on see turvaline (pea muidugi meeles lukustada kõik, kuhu tahad sellele kontole ligi pääseda). See takistab teistel lõimedel lukustatud koodi käivitamist. Samuti takistab see eespool mainitud mitme protsessori käskude järjestamise probleemi. Probleem on selles, et lukustus on aeglase jõudlusega ja kui kasutad lukku teistes mitteseotud kohtades, võib see blokeerida teisi lõime.
Parim
Interlocked.Increment (viide sellele vastavale loendurile);
See on ohutu ja väga tõhus. See teostab lugemise, suurendamise ja kirjutamise kolm operatsiooni ühes aatomis ilma katkestusteta keskel. Kuna see ei mõjuta muud koodi, ei pea sa mujal lukke meelde jätma. Ja see on ka väga kiire (nagu MSDN ütleb, tänapäeva protsessoritel on see tihti lihtsalt käsk).
Aga ma pole päris kindel, kas see suudab lahendada ka CPU käskude järjestamise probleemi või peab seda kasutama koos volatile'i ja selle kasvuga.
Lisa: Milliseid probleeme lahendab volatiilne hästi?
Kuna volatiilsed ei saa mitmelõimelist takistada, mida ta siis teha saab? Hea näide on, et sul on kaks lõime, üks kirjutab alati muutujale, oletame, et see muutuja on queneLength, ja teine loeb alati andmeid sellest muutujast. Kui queueLenght ei ole volatiilne, võib lõim A lugeda 5 korda, kuid lõim B võib näha hilinenud andmeid või isegi vales järjekorras. Üks lahendus on kasutada lukku, aga antud juhul võib kasutada ka volatile'i. See tagab, et lõim B näeb alati viimast lõime A kirjutatud andmeid, kuid see loogika töötab ainult siis, kui sa seda kirjutades ei loe, ja kui sa ei kirjuta seda lugemise ajal. Kui mitu lõime tahavad teha lugemise-muutmise-kirjutamise operatsioone, tuleb kasutada Interlocked või Locked.
|