Yazılım Geliştirme: Değişikliği Yönetin, Güvenli Arayüz Konu

Adanali

Active member
Yazılım Geliştirme: Değişikliği Yönetin, Güvenli Arayüz Konu


  1. Yazılım Geliştirme: Değişikliği Yönetin, Güvenli Arayüz Konu

Modeller, modern yazılımın geliştirilmesinde önemli bir soyutlamadır. Açıkça tanımlanmış terminoloji, temiz dokümantasyon ve öğrenme en iyisinden sunarlar. Bugünkü makalede, rekabet modelleriyle yolculuğuma devam ediyorum ve değişimle ilgileniyorum. İplik güvenli arayüzü, nesnelerin senkronizasyonu için kanıtlanmış bir modeldir.










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.













En iyi durumda, bir sınıfın üyelerinin tüm işlevlerini bir blokla koruma fikri, bir performans sorununa ve en kötü durumda bir durak durumuna yol açar.

Bir Duruş


Aşağıdaki küçük kod parçasının bir durak vardır:



struct Critical{
void memberFunction1(){
lock(mut);
memberFunction2();
...
}

void memberFunction2(){
lock(mut);
...
}

mutex mut;
};

Critical crit;
crit.memberFunction1();


Çağrı crit.memberFunction1 Mutex'e neden olur mut İki kez çekilir. Basitlik nedeniyle, kilit bir alan kilididir. İşte iki sorun:



  • Eğer lock Özyinelemeli bir kilit lock(mut) İşlevde memberFunction2 gereksiz.
  • Eğer lock İkincisi, kayda değer olmayan bir blok lock(mut) İçinde memberFunction2 belirsiz davranış için. Bu genellikle bir çıkmazdır.
İplik güvenli arayüzü her iki problemi de ortadan kaldırır.

İplik Güvenli Arayüz


Thread Safe'ın arayüzünün basit bir fikri budur:

  • Tüm arayüz işlevleri (public) Bir blok kullanın.
  • Tüm uygulama işlevleri (protected VE privat) bir blok kullanmamalıdır.
  • Arayüz işlevleri yalnızca uygulama işlevlerini hatırlar, ancak arayüz işlevi yoktur.
Aşağıdaki program, iş parçacığı güvenli arayüzünün kullanımını göstermektedir:



// threadSafeInterface.cpp

#include <iostream>
#include <mutex>
#include <thread>

class Critical{

public:
void interface1() const {
std::lock_guard<std::mutex> lockGuard(mut);
implementation1();
}

void interface2(){
std::lock_guard<std::mutex> lockGuard(mut);
implementation2();
implementation3();
implementation1();
}

private:
void implementation1() const {
std::cout << "implementation1: "
<< std::this_thread::get_id() << 'n';
}
void implementation2(){
std::cout << " implementation2: "
<< std::this_thread::get_id() << 'n';
}
void implementation3(){
std::cout << " implementation3: "
<< std::this_thread::get_id() << 'n';
}


mutable std::mutex mut; // (1)

};

int main(){

std::cout << 'n';

std::thread t1([]{
const Critical crit;
crit.interface1();
});

std::thread t2([]{
Critical crit;
crit.interface2();
crit.interface1();
});

Critical crit;
crit.interface1();
crit.interface2();

t1.join();
t2.join();

std::cout << 'n';

}


Ana iş parçacığı da dahil olmak üzere üç iş parçacığı, Critical. İplik Güvenli Arayüz sayesinde, genel FIP'lerin tüm görüşleri senkronize edilmiştir. Muteks mut (1) satırında değiştirilebilir ve sabit üye işlevinde olabilir interface1 kullanılabilir.

Thread Safe'ın arayüzünün avantajları üçlü:

  • Muteks'e özyinelemeli bir çağrı mümkün değildir. Recurgent olmayan bir muteksin özyinelemeli çağrıları genellikle belirsiz davranışlardır ve bir durak durumunda sonuçlanır.
  • Program minimum bir blok ve dolayısıyla minimum bir senkronizasyon kullanır. Bir kullanımı std::recursive_mutex Sınıf üyesinin her işlevinde Critical Pahalı bir senkronizasyona yol açacaktır.
  • Kullanıcının bakış açısından Critical Senkronizasyon yalnızca uygulamanın bir ayrıntısıdır çünkü kullanımı kolaydır.
Arayüzün her fonksiyon üyesi, çalışmalarını uygulamanın ilgili üye işlevine devrediyor. Dolaylı aşırı yük, güvenli arayüzün tipik bir dezavantajıdır.

Programın baskısı, üç iş parçacığının yuvalanmasını gösterir.









İplik güvenli arayüzünün uygulanması kolay görünse de, dikkate alınması gereken iki ana tehlike vardır.

İtilmiş


Statik sınıfın veya sanal arayüzlerin bir üyesinin kullanılması özel bakım gerektirir.

Statik üyeler

Sınıfınızın sabit olmayan statik bir üyesi varsa, sınıf örneklerindeki üyelerin tüm çağrılarını senkronize etmelisiniz.



class Critical{

public:
void interface1() const {
std::lock_guard<std::mutex> lockGuard(mut);
implementation1();
}
void interface2(){
std::lock_guard<std::mutex> lockGuard(mut);
implementation2();
implementation3();
implementation1();
}

private:
void implementation1() const {
std::cout << "implementation1: "
<< std::this_thread::get_id() << 'n';
++called;
}
void implementation2(){
std::cout << " implementation2: "
<< std::this_thread::get_id() << 'n';
++called;
}
void implementation3(){
std::cout << " implementation3: "
<< std::this_thread::get_id() << 'n';
++called;
}

inline static int called{0}; // (1)
inline static std::mutex mut;

};


Şimdi sınıf var Critical Statik Üye called (32) Uygulama işlevlerinin çağrıldığı sıklığı saymak. Tüm vakalar Critical Aynı statik üyesi kullanın ve bu nedenle senkronize edilmelidir. C ++ 17'den beri, statik veri öğeleri de inline ilan edilmek. Statik verilerin bir üyesi sınıfın tanımlanmasında tanımlanabilir ve başlatılabilir.

Sanallık

Sanal bir arayüz işlevini boğarsanız, overcsco işlevinin de bir blok kullandığından emin olmak gerekir. privat VE.



// threadSafeInterfaceVirtual.cpp

#include <iostream>
#include <mutex>
#include <thread>

class Base{

public:
virtual void interface() {
std::lock_guard<std::mutex> lockGuard(mut);
std::cout << "Base with lock" << 'n';
}
virtual ~Base() = default;
private:
std::mutex mut;
};

class Derived: public Base{

void interface() override {
std::cout << "Derived without lock" << 'n';
}

};

int main(){

std::cout << 'n';

Base* base1 = new Derived;
base1->interface();

Derived der;
Base& base2 = der;
base2.interface();

std::cout << 'n';

}


Çağrıldığında base1->interface VE base2.interface Statik verilerin türüdür base1 VE base2 Base Ve bu yüzden interface erişilebilir. Üye işlevinden beri interface Sanal, çağrıya dinamik tip denir Derived. Son olarak, özel üyelerin işlevi interface sınıf Derived isminde.

Programın çıktısı Derived.









Bu sorunu çözmenin iki tipik yolu vardır:

  • Arabirim işlevi, ek olmayan bir üye işlevi haline gelir. Bu teknolojiye NVI (virtual olmayan arayüz) denir. Virtual üye işlevi, temel sınıf arayüz işlevinin işlevini garanti eder Base Kullanılır. Ayrıca, arayüz işlevinin üzerine yazın override Bir derleme hatasına çünkü arayüz işlevi interface Sanal değil.
  • Üye işlevi bildirildi interface Bir final olarak: virtual void interface() final. Sayesinde final nasıl üzerine yazmaya yol açar final Bir derleme hatası için beyan edilen sanal üyenin işlevi.
Bu sanallık zorluğunu çözmek için iki yol sunmuş olmama rağmen, dilin tercih edilmesini şiddetle tavsiye ederim. Geç bir bağlantıya (sanallığa) ihtiyacınız yoksa, erken bağ kullanmanız gerekir. NVI hakkında daha fazla bilgi makalemde: Yazılımın geliştirilmesindeki modeller: model yöntemi.

Sırada ne var?


Korumalı süspansiyon, değişimle yüzleşmek için başka bir strateji kullanır. Değişikliği ile sonuçlandığında rapor. Bir sonraki makalemde, tutulan süspansiyon hakkında daha ayrıntılı olarak gideceğim.


(RME)




Ne yazık ki, bu bağlantı artık geçerli değil.

Boşa harcanan eşyalara olan bağlantılar, 7 günlük daha büyükse veya çok sık çağrılmışsa gerçekleşmez.


Bu makaleyi okumak için bir Haberler+ paketine ihtiyacınız var. Şimdi yükümlülük olmadan bir hafta deneyin – yükümlülük olmadan!
 
Üst