C ++ 26'da ertelenmiş şikayet: Güncelleme ve tehlikeli bölümleri okumak
Rekabetle ilgili yaygın bir sorun, ABA sorunudur. Bu, her zaman aynı değeri döndüren iki kez değişken okuduğunuz anlamına gelir. Bu nedenle, ortada hiçbir şeyin değişmediği sonucuna varır. Ama B.'yi unuttun
Rainer Grimm yıllardır yazılım mimarı, ekip ve eğitim müdürü olarak çalıştı. C ++ programlama dilleri, Python ve Haskell hakkında makaleler yazmayı seviyor, ancak uzman konferanslarla konuşmayı da seviyor. Modern C ++ blogunda, C ++ tutkusuyla yoğun bir şekilde ilgileniyor.
Aşağıdaki senaryo sorunu sunar.
Bir benzetme
Senaryo arabanızda oturuyor ve trafik ışığının yeşil olmasını bekliyor. Bizim durumumuzda, B ve kırmızı için yeşil A içindir. Sıradaki nedir?
Ya iş parçacığı (süreçler)? Şimdi çok resmi olarak.
Atomik çarpma
Aşağıdaki kodda, işlev çoğalır fetch_mult (1) A std::atomic<T>&ki mult Paylaşılır.
// fetch_mult.cpp
#include <atomic>
#include <iostream>
template <typename T>
T fetch_mult(std::atomic<T>& shared, T mult){ // 1
T oldValue = shared.load(); // 2
while (!shared.compare_exchange_strong(oldValue, oldValue * mult)); // 3
return oldValue;
}
int main(){
std::atomic<int> myInt{5};
std::cout << myInt << 'n';
fetch_mult(myInt,5);
std::cout << myInt << 'n';
}
shared.compare_exchange_strong(expected, desired)(3) Aşağıdaki davranışa sahiptir:
ABA'yı blokları olmayan bir veriye dayanarak göstermek istiyorum.
Bloksuz bir yığın
Zincirli bir liste olarak uygulanan bloklar olmadan bir yığın kullanıyorum. Yığın yalnızca iki işlemi destekler.
Stack: TOP -> head -> headNext -> ...
Aba eylemde
Aşağıdaki yığınla başlayalım:
Stack: TOP -> A -> B -> C
Filo 1 aktiftir ve yığın kafasını çıkarmak istiyor.
İş parçacığı 1 pop algoritmasını bitirmeden önce, iş parçacığı 2 etkinleştirilir.
Stack: TOP -> B -> C
Konu 1, sadece olup olmadığını kontrol etmek için planlanmıştır A == head. A == headhale gelmek headNextYani b, yeni kafaya. Ancak B zaten ortadan kaldırıldı. Bu nedenle, programın belirsiz davranışları vardır.
ABA sorunu için yardım var.
ABA için çare
ABA'nın kavramsal problemini anlamak nispeten kolaydır. Bir düğüm gibi B == headNext başka bir düğüm olsa bile silindi A == headona atıfta bulundu. Sorunumuzun çözümü, düğümün erken iptal edilmesini önlemektir. İşte bazı çözümler.
Sonraki üç teknik, ertelenmiş ıslah fikrine dayanmaktadır.
Çöp toplama, değişkenlerin ancak artık gerekli olmadıkları takdirde ortadan kaldırılacağını garanti eder. Umut verici görünüyor, ancak büyük bir dezavantajı var. Çoğu çöp koleksiyoncu bloksuz değildir. Bu nedenle, blokları olmayan bir veriniz var, ancak genel sistem bloksız değil.
Wikipedia'dan: Pointers Tehlike:
Bir tehlike sisteminde, her iş parçacığı, hangi iş parçacığı düğümlerinin erişebileceğini gösteren tehlikeli bölümlerin bir listesini yönlendirir. (Bu “liste” birçok sistemdeki yalnızca bir veya iki öğeyle sınırlı olabilir.) Tehlikeli bölümler listesindeki düğümler başka bir iş parçacığı tarafından değiştirilmemeli veya serbest bırakılmamalıdır. … Bir iş parçacığı bir düğümü kaldırmak istiyorsa, “daha sonra yayınlanması” gereken bir düğüm listesine dayanır, ancak düğümün belleğini yalnızca tehlikeler listesi başka bir iş parçacığı içermiyorsa serbest bırakır. Özel bir çöp toplama iş parçacığı bu pişirme kılavuzu koleksiyonunu gerçekleştirebilir (“Daha sonra sürüm” listesi tüm iş parçacıkları tarafından paylaşılırsa); Alternatif olarak, “Paylaşım” listesinin temizlenmesi, her çalışma iş parçacığı tarafından bir işlemin bir parçası olarak “pop” olarak gerçekleştirilebilir.
RCU için READ COpey UPaul McKenney tarafından geliştirilen ve 2002'den beri Linux çekirdeğinde geliştirilen bir senkronizasyon teknolojisi olan Pdate, neredeyse yazılarak korunan veri yapıları için kullanıldı.
Fikir oldukça basit ve kısaltmayı takip ediyor. Verileri değiştirmek için verilerin bir kopyasını oluşturun ve bu kopyayı değiştirin. Aksine, tüm okuyucular orijinal verilerle çalışır. Okuyucu yoksa, verilerin yapısı tereddüt etmeden kopya ile değiştirilebilir.
Sırada ne var?
Bir sonraki makalemde, ertelenmiş ıslah içeren bloklar olmadan bir yığın uygulayacağım.
(RME)
C ++ 26'da ertelenmiş şikayet: Güncelleme ve tehlikeli bölümleri okumak
Rekabetle ilgili yaygın bir sorun, ABA sorunudur. Bu, her zaman aynı değeri döndüren iki kez değişken okuduğunuz anlamına gelir. Bu nedenle, ortada hiçbir şeyin değişmediği sonucuna varır. Ama B.'yi unuttun

Rainer Grimm yıllardır yazılım mimarı, ekip ve eğitim müdürü olarak çalıştı. C ++ programlama dilleri, Python ve Haskell hakkında makaleler yazmayı seviyor, ancak uzman konferanslarla konuşmayı da seviyor. Modern C ++ blogunda, C ++ tutkusuyla yoğun bir şekilde ilgileniyor.

Aşağıdaki senaryo sorunu sunar.
Bir benzetme
Senaryo arabanızda oturuyor ve trafik ışığının yeşil olmasını bekliyor. Bizim durumumuzda, B ve kırmızı için yeşil A içindir. Sıradaki nedir?
- Trafik ışığına bakın ve kırmızıdır (a).
- Sıkıcı olduğu için akıllı telefonunuzdaki haberlere bakın ve zamanı unutun.
- Trafik ışıklarına tekrar bakın. Kahretsin hala kırmızı (a).
Ya iş parçacığı (süreçler)? Şimdi çok resmi olarak.
- Tartışma 1 bir değişkeni okur var A değeri ile
- Filo 1 kesintiye uğradı ve iplik 2 gerçekleştirildi.
- Tartışma 2 değişkeni değiştirir var A B'den A'ya
- Konu 1, yürütme ile başlar ve değişkenin değerini kontrol eder var; Değişkenlerin değerinden beri var Aynı kalıntılar, Konu 1 çalışmasına devam ediyor,
Atomik çarpma
Aşağıdaki kodda, işlev çoğalır fetch_mult (1) A std::atomic<T>&ki mult Paylaşılır.
// fetch_mult.cpp
#include <atomic>
#include <iostream>
template <typename T>
T fetch_mult(std::atomic<T>& shared, T mult){ // 1
T oldValue = shared.load(); // 2
while (!shared.compare_exchange_strong(oldValue, oldValue * mult)); // 3
return oldValue;
}
int main(){
std::atomic<int> myInt{5};
std::cout << myInt << 'n';
fetch_mult(myInt,5);
std::cout << myInt << 'n';
}
shared.compare_exchange_strong(expected, desired)(3) Aşağıdaki davranışa sahiptir:
- Karşılaştırma false Sonuçlar, Will expected AÇIK shared ayarlamak.
- Atom karşılaştırması true Sonuçlar, Will shared Aynı atom işleminde expected ayarlamak.
ABA'yı blokları olmayan bir veriye dayanarak göstermek istiyorum.
Bloksuz bir yığın
Zincirli bir liste olarak uygulanan bloklar olmadan bir yığın kullanıyorum. Yığın yalnızca iki işlemi destekler.
- Üst nesneyi parmaklayın ve bir işaretçi döndürün.
- Belirtilen nesneyi yığın üzerine itin.
- Baş düğümü alın: KAFA
- Aşağıdaki düğümü alın: HeadNext
- Yapmak HeadNext yeni kafaya ne zaman KAFA Hala yığının başı
Stack: TOP -> head -> headNext -> ...
Aba eylemde
Aşağıdaki yığınla başlayalım:
Stack: TOP -> A -> B -> C
Filo 1 aktiftir ve yığın kafasını çıkarmak istiyor.
İş parçacığı 1 pop algoritmasını bitirmeden önce, iş parçacığı 2 etkinleştirilir.
Stack: TOP -> B -> C
- Tartışma 2 kaldırıldı B ve Sil B
- Tartışma 2 bir arkaya iter
Konu 1, sadece olup olmadığını kontrol etmek için planlanmıştır A == head. A == headhale gelmek headNextYani b, yeni kafaya. Ancak B zaten ortadan kaldırıldı. Bu nedenle, programın belirsiz davranışları vardır.
ABA sorunu için yardım var.
ABA için çare
ABA'nın kavramsal problemini anlamak nispeten kolaydır. Bir düğüm gibi B == headNext başka bir düğüm olsa bile silindi A == headona atıfta bulundu. Sorunumuzun çözümü, düğümün erken iptal edilmesini önlemektir. İşte bazı çözümler.
- İşaretli bir duruma referans
Sonraki üç teknik, ertelenmiş ıslah fikrine dayanmaktadır.
Çöp toplama, değişkenlerin ancak artık gerekli olmadıkları takdirde ortadan kaldırılacağını garanti eder. Umut verici görünüyor, ancak büyük bir dezavantajı var. Çoğu çöp koleksiyoncu bloksuz değildir. Bu nedenle, blokları olmayan bir veriniz var, ancak genel sistem bloksız değil.
Wikipedia'dan: Pointers Tehlike:
Bir tehlike sisteminde, her iş parçacığı, hangi iş parçacığı düğümlerinin erişebileceğini gösteren tehlikeli bölümlerin bir listesini yönlendirir. (Bu “liste” birçok sistemdeki yalnızca bir veya iki öğeyle sınırlı olabilir.) Tehlikeli bölümler listesindeki düğümler başka bir iş parçacığı tarafından değiştirilmemeli veya serbest bırakılmamalıdır. … Bir iş parçacığı bir düğümü kaldırmak istiyorsa, “daha sonra yayınlanması” gereken bir düğüm listesine dayanır, ancak düğümün belleğini yalnızca tehlikeler listesi başka bir iş parçacığı içermiyorsa serbest bırakır. Özel bir çöp toplama iş parçacığı bu pişirme kılavuzu koleksiyonunu gerçekleştirebilir (“Daha sonra sürüm” listesi tüm iş parçacıkları tarafından paylaşılırsa); Alternatif olarak, “Paylaşım” listesinin temizlenmesi, her çalışma iş parçacığı tarafından bir işlemin bir parçası olarak “pop” olarak gerçekleştirilebilir.
RCU için READ COpey UPaul McKenney tarafından geliştirilen ve 2002'den beri Linux çekirdeğinde geliştirilen bir senkronizasyon teknolojisi olan Pdate, neredeyse yazılarak korunan veri yapıları için kullanıldı.
Fikir oldukça basit ve kısaltmayı takip ediyor. Verileri değiştirmek için verilerin bir kopyasını oluşturun ve bu kopyayı değiştirin. Aksine, tüm okuyucular orijinal verilerle çalışır. Okuyucu yoksa, verilerin yapısı tereddüt etmeden kopya ile değiştirilebilir.
Sırada ne var?
Bir sonraki makalemde, ertelenmiş ıslah içeren bloklar olmadan bir yığın uygulayacağım.
(RME)