Const, C ++ 11'de iş parçacığı güvenli anlamına mı geliyor?


116

Bunu duyduğuma constaraçlar parçacığı güvenli içinde 11 C ++ . Bu doğru mu?

Demek oluyor mu consteşdeğer şimdi olduğu Java'nın 's synchronized?

Onlar tükeniyor anahtar kelimeler ?


1
C ++ - SSS genellikle C ++ topluluğu tarafından yönetilir ve sohbetimize gelip bize fikirlerinizi sorabilirsiniz.
Puppy

@DeadMG: C ++ - sss ve görgü kurallarından habersizdim, bir yorumda önerildi.
K-ballo

2
Sabit'in iş parçacığı güvenli anlamına geldiğini nereden duydunuz?
Mark B

2
@Mark B: Herb Sutter ve Bjarne Stroustrup bunu Standard C ++ Foundation'da söylüyorlardı , cevabın altındaki bağlantıya bakın.
K-ballo

İNSANLARA NOT BURAYA GELECEK: Gerçek soru olmadığını DEĞİLDİR const araçlar parçacığı güvenli. Bu saçma olurdu, çünkü aksi takdirde devam edip her iş parçacığı güvenli yöntemi olarak işaretleyebilmeniz gerektiği anlamına gelir const. Aksine, gerçekten sorduğumuz soru const IMPLIES iş parçacığı için güvenli ve bu tartışma bununla ilgili.
user541686

Yanıtlar:


132

Bunu duyduğuma constaraçlar parçacığı güvenli içinde 11 C ++ . Bu doğru mu?

Öyle biraz gerçek ...

Standart Dil'in iş parçacığı güvenliği konusunda söylediği şey bu :

[1.10 / 4] İki sentezleme değerlendirmeleri çakışma bunlardan biri bir bellek konumu (1.7) diğeri de veya bu değiştirir aynı bellek yeri değiştirmesi durumunda.

[1.10 / 21] Bir programın yürütülmesi,farklı iş parçacıklarında en az biri atomik olmayan ve ikisi de diğerinden önce gerçekleşmeyen iki çakışan eylemiçeriyorsa bir veri yarışı içerir. Bu tür herhangi bir veri yarışı, tanımlanmamış davranışla sonuçlanır.

Bu, bir veri yarışının gerçekleşmesi için yeterli koşuldan başka bir şey değildir :

  1. Belirli bir şey üzerinde aynı anda gerçekleştirilen iki veya daha fazla eylem vardır; ve
  2. Bunlardan en az biri bir yazı.

Standart Kütüphanesi biraz daha gidiyor, o üzerine inşa:

[17.6.5.9/1] Bu bölüm, uygulamaların veri yarışlarını (1.10) önlemek için karşılaması gereken gereksinimleri belirtir. Her standart kitaplık işlevi, aksi belirtilmedikçe her bir gereksinimi karşılamalıdır. Uygulamalar, aşağıda belirtilenler dışındaki durumlarda veri yarışlarını engelleyebilir.

[17.6.5.9/3] Bir C ++ standart kitaplık işlevi, nesnelere doğrudan veya dolaylı olarak işlevin const olmayanargümanlarıaracılığıyla erişilmediği sürece, geçerli evre dışındaki evreler tarafından erişilebilen nesneleri (1.10) doğrudan veya dolaylı olarak değiştirmemelidirthis.

basit bir deyişle, constnesneler üzerindeki işlemlerin iş parçacığı açısından güvenli olmasını beklediğini söylüyor . Bu, Standart Kitaplığınconst kendi türlerinizdeki nesneler üzerinde işlemler yapılmadığı sürece bir veri yarışı getirmeyeceği anlamına gelir.

  1. Tamamen okumalardan oluşur - yani hiçbir yazı yoktur -; veya
  2. Yazmaları dahili olarak senkronize eder.

Bu beklenti türlerinizden biri için geçerli değilse, Standart Kitaplığın herhangi bir bileşeni ile doğrudan veya dolaylı olarak kullanılması bir veri yarışına neden olabilir . Sonuç olarak, Standart Kitaplık açısından iş parçacığı açısından güvenliconst anlamına gelir . Bunun sadece bir sözleşme olduğunu ve derleyici tarafından uygulanmayacağını unutmamak önemlidir , eğer onu bozarsanız tanımsız davranışlarla karşılaşırsınız ve kendi başınıza olursunuz. Mevcut olup olmaması, kod üretimini etkilemeyecektir - en azından veri yarışları açısından -.const

Demek oluyor mu consteşdeğer şimdi olduğu Java'nın 's synchronized?

Hayır . Bir şey değil...

Bir dikdörtgeni temsil eden aşağıdaki aşırı basitleştirilmiş sınıfı düşünün:

class rect {
    int width = 0, height = 0;

public:
    /*...*/
    void set_size( int new_width, int new_height ) {
        width = new_width;
        height = new_height;
    }
    int area() const {
        return width * height;
    }
};

Üye fonksiyonlu area olan iş parçacığı güvenli ; değil çünkü consttamamen okuma işlemlerinden oluşuyor. Hiçbir yazma işlemi yoktur ve bir veri yarışının gerçekleşmesi için en az bir yazma işlemi gereklidir . Bu, istediğiniz kadar konu başlığından arayabileceğiniz areave her zaman doğru sonuçlar alacağınız anlamına gelir .

Bunun iş parçacığı için güvenlirect olduğu anlamına gelmediğini unutmayın . Aslında, onun kolay bir çağrı olmadığını görmek için vardı yapılan bir çağrı aynı anda gerçekleşmesi belirli bir üzerine , daha sonra (bozuk değerler üzerinde bile ya) eski bir genişlik ve yeni bir yüksekliğe dayalı olarak sonucun hesaplanması bitebileceğini .areaset_sizerectarea

Ancak rectsorun değil , sonuçta iş parçacığı için güvenliconst olması beklenmiyor . Öte yandan bildirilen bir nesne , hiçbir yazma mümkün olmadığından iş parçacığı açısından güvenli olacaktır (ve eğer orijinal olarak bildirilmiş bir şeyi düşünüyorsanız , o zaman tanımsız davranış elde edersiniz ve işte budur).const rectconst_castconst

Öyleyse bu ne anlama geliyor?

Varsayalım ki - argüman uğruna - çarpma işlemlerinin son derece maliyetli olduğunu ve mümkün olduğunda onlardan kaçınmamız daha iyi olur. Alanı yalnızca talep edilirse hesaplayabilir ve daha sonra tekrar talep edilmesi durumunda önbelleğe alabiliriz:

class rect {
    int width = 0, height = 0;

    mutable int cached_area = 0;
    mutable bool cached_area_valid = true;

public:
    /*...*/
    void set_size( int new_width, int new_height ) {
        cached_area_valid = ( width == new_width && height == new_height );
        width = new_width;
        height = new_height;
    }
    int area() const {
        if( !cached_area_valid ) {
            cached_area = width;
            cached_area *= height;
            cached_area_valid = true;
        }
        return cached_area;
    }
};

[Bu örnek, çok yapay görünüyorsa, zihinsel yerini alabilecek intbir tarafından çok büyük dinamik olarak ayrılan tamsayı doğal olmayan bir iş parçacığı güvenli ve kendisi için çarpımları son derece masraflıdır.]

Üye işlev area artık evreli artık yazma yapıyor ve içten senkronize edilmez. Sorun mu? Çağrısı areabir parçası olarak ortaya çıkabilir kopyalamaya karşı yapıcı bir başka nesnenin, bu tür yapıcı bir bazı operasyonla denilen olabilirdi standart konteyner , ve bu noktada standart kütüphane bu işlem bir şekilde davranmasını bekler okuma konusunda veri yarışları . Ama yazılar yazıyoruz!

Doğrudan veya dolaylı olarak standart bir konteynererect bir tane koyar koymaz , Standart Kitaplık ile bir sözleşme yapıyoruz . Bu sözleşmeyi yerine getirirken bir işlevde yazmaya devam etmek için, bu yazıları dahili olarak senkronize etmemiz gerekir:const

class rect {
    int width = 0, height = 0;

    mutable std::mutex cache_mutex;
    mutable int cached_area = 0;
    mutable bool cached_area_valid = true;

public:
    /*...*/
    void set_size( int new_width, int new_height ) {
        if( new_width != width || new_height != height )
        {
            std::lock_guard< std::mutex > guard( cache_mutex );
        
            cached_area_valid = false;
        }
        width = new_width;
        height = new_height;
    }
    int area() const {
        std::lock_guard< std::mutex > guard( cache_mutex );
        
        if( !cached_area_valid ) {
            cached_area = width;
            cached_area *= height;
            cached_area_valid = true;
        }
        return cached_area;
    }
};

areaFonksiyonu iş parçacığı için güvenli yaptığımıza dikkat edin , ancak rectyine de iş parçacığı için güvenli değildir . Bir çağrı areaçağrı için aynı anda oluyor set_sizehala atamaları beri, yanlış değer hesaplayan sona erebilir widthve heightMuteksleri tarafından korunmaz.

Eğer gerçekten bir iş parçacığı güvenli isteseydik, iş parçacığı güvenli olmayanlarırect korumak için bir senkronizasyon ilkelini kullanırdık . rect

Onlar tükeniyor anahtar kelimeler ?

Evet onlar. İlk günden beri anahtar kelimeleri tükeniyor .


Kaynak : Bilmiyorsunuz constvemutable - Herb Sutter


6
@Ben Voigt: Anladığım kadarıyla olduğuna C ++ 11 için şartname std::stringzaten yasakladığı bir manada söylenmiştir COW . Yine de ayrıntıları hatırlamıyorum ...
K-ballo

3
@BenVoigt: Hayır. Bu sadece bu tür şeylerin senkronize olmamasını, yani iş parçacığı güvenli olmamasını engelleyecektir. C ++ 11 zaten açıkça COW'u yasaklıyor - bu belirli pasajın bununla hiçbir ilgisi yok ve COW'u yasaklamıyor.
Puppy

2
Bana öyle geliyor ki mantıksal bir boşluk var. [17.6.5.9/3], "doğrudan veya dolaylı olarak değiştirilmemelidir" diyerek "çok fazla" yasaklar; o, "doğrudan ya da dolaylı bir veri yarışı koymayacaklardır" demeli sürece bir atom yazma yerde tanımlanır değil bir "değiştirme" olarak. Ama bunu hiçbir yerde bulamıyorum.
Andy Prowl

1
Muhtemelen burada tüm amacımı biraz daha netleştirdim: isocpp.org/blog/2012/12/… Yine de yardım etmeye çalıştığınız için teşekkür ederim.
Andy Prowl

1
Bazen bunun gibi bazı standart paragrafları yazmaktan kimin sorumlu olduğunu (veya doğrudan dahil olanların) kim olduğunu merak ediyorum.
pepper_chico
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.