SORU
1 Mayıs 2015, Cuma


Nasıl C hareketli tip uyumu ile mi ilgileneyim ?

Tasarım değil hareketli ne de kopya constructable. Bu bir dışlama tutan A, almazsınız bir sınıf-hareket-yapıcı varsayılan anlamına gelir.

Nasıl bu tip A hareketli iş parçacığı için güvenli bir şekilde yapmak istiyorsunuz?

CEVAP
1 Mayıs 2015, Cuma


Hadi kod biraz ile başlayın:

class A
{
    using MutexType = std::mutex;
    using ReadLock = std::unique_lock<MutexType>;
    using WriteLock = std::unique_lock<MutexType>;

    mutable MutexType mut_;

    std::string field1_;
    std::string field2_;

public:
    ...

Gerçekten yararlanmak istemiyoruz orada oldukça düşündüren bazı tür adları C 11, ama çok daha yararlı olmak C 14 verdim. Sabırlı ol, oraya da geleceğiz.

Soru için aşağı kaynar:

Nasıl bu sınıf için hareket yapıcı ve hareket atama operatörü yazacağım?

Hareket kurucu ile başlayacağız.

Yapıcı Hareket

Üyesi mutex mutable yapılmış olduğunu unutmayın. Kesinlikle bu konuşma hareket üyeleri için gerekli değil, ama aynı zamanda kopya üyeleri istiyorum varsayıyorum. Eğer durum böyle değilse, zaman uyumu mutable yapmaya gerek yok.

A inşa ederken this->mut_ kilit gerekmez. Ama (Taşı veya kopyala) inşa ettiğiniz nesne mut_ kilitlemek gerekir. Bu çok gibi yapılabilir:

    A(A&& a)
    {
        WriteLock rhs_lk(a.mut_);
        field1_ = std::move(a.field1_);
        field2_ = std::move(a.field2_);
    }

a.mut_ kilitli sonra this üyeleri ilk varsayılan inşa ettik, sonra da onlara değer atamak unutmayın.

Atama Taşıyın

Hareket atama operatörü ise başka bir konuyu da belirtin veya atama ifadenin oluşturduğu erişme bilmediğiniz için önemli ölçüde daha karmaşıktır. Ve genel olarak, aşağıdaki senaryoyu karşı korunmak için:

// Thread 1
x = std::move(y);

// Thread 2
y = std::move(x);

Burada doğru yukarıdaki senaryo Muhafızları harekete atama operatörü:

    A& operator=(A&& a)
    {
        if (this != &a)
        {
            WriteLock lhs_lk(mut_, std::defer_lock);
            WriteLock rhs_lk(a.mut_, std::defer_lock);
            std::lock(lhs_lk, rhs_lk);
            field1_ = std::move(a.field1_);
            field2_ = std::move(a.field2_);
        }
        return *this;
    }

Bir std::lock(m1, m2) iki uyumu kilitlemek için, sadece onları birbiri ardına kilitleme yerine kullanmanız gerektiğini unutmayın. Eğer onları birbiri ardına kilitlerseniz, o zaman iki konu yukarıda gösterildiği gibi ters sırayla iki nesne atamak, kilitlenme alabilirsiniz. std::lock bu kilitlenme önlemek için.

Kurucu Kopyalayın

Kopya üyeleri sormadım, ama onlar hakkında şimdi (sen değilsen, birileri onları gerekir) konuşabiliriz.

    A(const A& a)
    {
        ReadLock  rhs_lk(a.mut_);
        field1_ = a.field1_;
        field2_ = a.field2_;
    }

Kopya yapıcı hareket ReadLock diğer WriteLock yerine kullanılır dışında yapıcı gibi görünüyor. Şu anda her ikisi de diğer adı aslında fark etmez std::unique_lock<std::mutex> ve bu.

Ama C 14, bunun iki seçeneği vardır:

    using MutexType = std::shared_timed_mutex;
    using ReadLock  = std::shared_lock<MutexType>;
    using WriteLock = std::unique_lock<MutexType>;

Buolabilirbir iyileştirme olabilir, ama kesinlikle değil. Ölçmek için olup olmadığını belirlemek gerekir. Ama bu değişiklik ile, bir kopyasını inşa etmekdanbirden çok iş parçacığı aynı anda oluşturduğu. C 11 çözüm size oluşturduğu değiştirilmiş olmasa bile bu tür konuları sıralı yapmak için zorlar.

Atama Kopyalayın

Bütünlüğü için, burada her şey okuduktan sonra oldukça kendini açıklayıcı olmalıdır kopya atama operatör,

    A& operator=(const A& a)
    {
        if (this != &a)
        {
            WriteLock lhs_lk(mut_, std::defer_lock);
            ReadLock  rhs_lk(a.mut_, std::defer_lock);
            std::lock(lhs_lk, rhs_lk);
            field1_ = a.field1_;
            field2_ = a.field2_;
        }
        return *this;
    }

Ve vb.

Diğer üyeler veya ücretsiz fonksiyonlara erişim A'In durumu da eğer birden çok iş parçacığı aynı anda onları arayabilir düşünüyorsanız korunması gerekir. Örneğin, burada swap:

    friend void swap(A& x, A& y)
    {
        if (&x != &y)
        {
            WriteLock lhs_lk(x.mut_, std::defer_lock);
            WriteLock rhs_lk(y.mut_, std::defer_lock);
            std::lock(lhs_lk, rhs_lk);
            using std::swap;
            swap(x.field1_, y.field1_);
            swap(x.field2_, y.field2_);
        }
    }

Eğer sadece std::swap işi bağlı, yanlış kilitleme parçalı yapı, std::swap DAHİLİ olarak gerçekleştireceği ve üç hamle arasında kilitleme kilidini unutmayın.

Gerçekten de, düşünmek swap mı içgörü API ihtiyacın olabilir sağlamak için bir "iş parçacığı güvenli" A, genel farklı olacak bir "non-thread-safe" API, çünkü bu "kilitleme parçalı yapı" sorunu.

Ayrıca karşı korumak için gereken "öz-swap". "öz-takas" olması bir no-op. not Kendini kontrol olmadan bir yinelemeli olarak aynı zaman uyumu kilitlerdi. Bu da MutexType std::recursive_mutex kullanarak öz-onay olmadan çözülebilir.

Güncelleme

Yakk aşağıda açıklamalarda kopyalama ve taşıma kurucular şeyler varsayılan inşa etme konusunda oldukça mutsuz (ve haklı). Bu konuda yeterince güçlü, hafıza harcamaya istekli öyle ki hissedesin, bu yüzden önleyebilirsiniz:

  • İhtiyacınız ne olursa olsun veri üyeleri olarak ekleyin. Bu üyeler korumalı veri önce gelmelidir:

    mutable MutexType mut_;
    ReadLock  read_lock_;
    WriteLock write_lock_;
    // ... other data members ...
    
  • Ve kurucular (kopya kurucu gibi) o zaman bunu:

    A(const A& a)
        : read_lock_(a.mut_)
        , field1_(a.field1_)
        , field2_(a.field2_)
    {
        read_lock_.unlock();
    }
    

Oops, Yakk bu güncelleştirmeyi tamamlamak için şansı vardı önce onun yorumunu sildim. Ama bu sorunu iterek, ve bu cevap bir çözüm almak için kredi hak ediyor.

Güncelleme 2

Ve dyp bu iyi bir öneri ile geldi:

    A(const A& a)
        : A(a, ReadLock(a.mut_))
    {}
private:
    A(const A& a, ReadLock rhs_lk)
        : field1_(a.field1_)
        , field2_(a.field2_)
    {}

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • pilslajt

    pilslajt

    20 HAZİRAN 2008
  • PomplamooseMusic

    PomplamooseM

    28 HAZİRAN 2008
  • Rickymon Tero

    Rickymon Ter

    1 Ocak 2007