En kötü (aslında çalışmaz)
Erişim değiştiricisini olarak counter
değiştirpublic volatile
Diğer insanların belirttiği gibi, bu tek başına aslında güvenli değildir. Bunun anlamı, volatile
birden fazla CPU üzerinde çalışan birden çok iş parçacığının verileri önbelleğe alıp talimatlarını yeniden sıralayabilmesidir.
Eğer öyleyse değil volatile
, ve CPU A değerini artırır, daha sonra CPU B aslında sorunlara neden olabilir daha sonra bir süre, kadar bu arttırılmış değer göremeyebilirsiniz.
Öyleyse volatile
, bu sadece iki CPU'nun aynı anda aynı verileri görmesini sağlar. Onlardan kaçınmaya çalıştığınız sorun olan okuma ve yazma işlemlerini bırakmasını engellemez.
En iyi ikinci:
lock(this.locker) this.counter++
;
Bunu yapmak güvenlidir ( lock
eriştiğiniz her yere hatırlamanız koşuluyla this.counter
). Diğer tüm evreler tarafından korunan diğer kodların yürütülmesini engeller locker
. Kilitleri kullanarak, yukarıdaki gibi çoklu CPU yeniden sıralama sorunlarını önler, bu harika.
Sorun, kilitleme yavaş ve eğer locker
gerçekten ilgili olmayan başka bir yerde yeniden kullanırsanız, o zaman diğer ipliklerinizi hiçbir sebeple bloke edebilirsiniz.
En iyi
Interlocked.Increment(ref this.counter);
Bu, güvenli bir şekilde kesilemeyen 'tek vuruşta' okuma, arttırma ve yazma işlemlerini yaptığı için güvenlidir. Bu nedenle, diğer kodları etkilemez ve başka bir yerde de kilitlemeyi hatırlamanız gerekmez. Ayrıca çok hızlıdır (MSDN'in söylediği gibi, modern CPU'larda, bu genellikle tam anlamıyla tek bir CPU talimatıdır).
Ancak, diğer CPU'ların bir şeyleri yeniden sıralaması veya geçici olarak artışı ile birleştirmeniz gerekiyorsa emin değilim.
InterlockedNotes:
- İNTERLOK EDİLMİŞ YÖNTEMLER HERHANGİ BİR ÇEKİRDEK VEYA İŞLEMCİ ÜZERİNDE TAMAMEN GÜVENLİDİR.
- Kilitli yöntemler, yürüttükleri talimatların etrafına tam bir çit uygular, bu nedenle yeniden sıralama gerçekleşmez.
- Birbirine kenetlenmiş yöntemlerin uçucu bir alana erişime ihtiyacı yoktur ve hatta desteklemezler , çünkü uçucu verilen alandaki işlemlerin etrafına yarım bir çit yerleştirilir ve kenetlenmiş tam çit kullanılır.
Dipnot: Uçucu olan aslında ne işe yarar.
As volatile
için bu kadar ne mulithread bu tür konuları engellemez? İyi bir örnek, biri her zaman bir değişkene (diyelim queueLength
) ve diğeri her zaman aynı değişkenten okuyan iki iş parçacığına sahip olduğunuzu söylemektir .
queueLength
Uçucu değilse , A iş parçacığı beş kez yazabilir, ancak B iş parçacığı bu yazma işlemlerini geciktirildiğini (hatta potansiyel olarak yanlış sırada) görebilir.
Bir çözüm kilitlemek olacaktır, ancak bu durumda uçucu da kullanabilirsiniz. Bu, B iş parçacığının her zaman A iş parçacığının yazdığı en güncel şeyi görmesini sağlar. Not Ancak bu mantık o sadece yazdığınız asla hiç okumamış yazarlar ve okuyucular varsa, işler ve şey sen yazma atomik değeri ise. Tek bir okuma-değiştirme-yazma işlemi yaptığınızda, Kilitli işlemlere gitmeniz veya bir Kilit kullanmanız gerekir.