C++26'ya genel bakış: ek kitaplık işlevleri ve eşzamanlılık

Adanali

Active member
C++26'ya genel bakış: ek kitaplık işlevleri ve eşzamanlılık


  1. C++26'ya genel bakış: ek kitaplık işlevleri ve eşzamanlılık

Eşzamanlılığa geçmeden önce C++26 kitaplığında iki özellik daha var: doygunluk aritmetiği ve hata ayıklama desteği.


Duyuru








Rainer Grimm uzun yıllardır yazılım mimarı, ekip ve eğitim yöneticisi olarak çalışmaktadır. C++, Python ve Haskell programlama dilleri üzerine makaleler yazmaktan hoşlanıyor, aynı zamanda özel konferanslarda sık sık konuşmaktan da hoşlanıyor. Modern C++ adlı blogunda C++ tutkusunu yoğun bir şekilde ele alıyor.













Doygunluk aritmetiği


İngilizce Wikipedia sayfası doygunluk aritmetiğini şu şekilde açıklamaktadır: Doygunluk aritmetiği toplama ve çarpma gibi tüm işlemlerin minimum ve maksimum değer arasındaki sabit bir aralıkla sınırlı olduğu aritmetiğin bir versiyonudur. Bir işlemin sonucu maksimumdan büyükse maksimuma ayarlanır (“kilitlenir”); minimumdan küçükse minimumda bloke edilir. Adı, uç değerlere ulaşıldığında değerin nasıl “doygun” hale geldiği; Maksimuma yapılacak ilave eklemeler veya minimumdan çıkarmalar sonucu değiştirmeyecektir.

C++26 bir dizi doygunluk aritmetik işlemini tanıttı: toplama, çıkarma, çarpma, bölme ve doygunluk dönüşümü. Belirtilen tamsayı veri türü T işlemin sonucunu temsil edemiyorsa, bunun yerine sonuç std::numeric_limits::min<T>() VEYA std::numeric_limits::max<T>() (hangisi daha yakınsa).

cppreference.com'da ayrıca bir açıklama içeren güzel bir örnek var std::add_sat:


#include <climits>&#13;
#include <limits>&#13;
#include <numeric>&#13;
&#13;
static_assert(CHAR_BIT == 8);&#13;
static_assert(UCHAR_MAX == 255);&#13;
&#13;
int main()&#13;
{&#13;
constexpr int a = std::add_sat(3, 4); // no saturation occurs, T = int&#13;
static_assert(a == 7);&#13;
&#13;
constexpr unsigned char b = std::add_sat<unsigned char>(UCHAR_MAX, 4); // saturated&#13;
static_assert(b == UCHAR_MAX);&#13;
&#13;
constexpr unsigned char c = std::add_sat(UCHAR_MAX, 4); // not saturated, T = int&#13;
// add_sat(int, int) returns int tmp == 259,&#13;
// then assignment truncates 259 % 256 == 3&#13;
static_assert(c == 3);&#13;
&#13;
// unsigned char d = std::add_sat(252, c); // Error: inconsistent deductions for T&#13;
&#13;
constexpr unsigned char e = std::add_sat<unsigned char>(251, a); // saturated&#13;
static_assert(e == UCHAR_MAX);&#13;
// 251 is of type T = unsigned char, `a` is converted to unsigned char value;&#13;
// might yield an int -> unsigned char conversion warning for `a`&#13;
&#13;
constexpr signed char f = std::add_sat<signed char>(-123, -3); // not saturated&#13;
static_assert(f == -126);&#13;
&#13;
constexpr signed char g = std::add_sat<signed char>(-123, -13); // saturated&#13;
static_assert(g == std::numeric_limits<signed char>::min()); // g == -128&#13;
}


T, her iki işlev bağımsız değişkeninin veri türüdür:


template< class T >&#13;
constexpr T add_sat( T x, T y ) noexcept;


Hata ayıklama desteği


C++26'nın hata ayıklama için üç işlevi vardır.

  • std::breakpoint çağrıldığında çalışan programı durdurur ve kontrolü hata ayıklayıcıya aktarır,
  • std::breakpoint_if_debugging aramalar std::breakpoint ne zaman hakkında std::is_debugger_present true geri gelmek,
  • std::is_debugger_present Bir programın bir hata ayıklayıcının kontrolü altında çalışıp çalışmadığını kontrol eder.
Bu, C++26 kütüphanesine ilk genel bakıştı. Hadi yarışmaya devam edelim.

C++26'da eş zamanlılığın baskın bir özelliği vardır:

std::execution


std::executionDaha önce Gönderenler/Alanlar olarak adlandırılan bu sistem, genel kaynaklarda (P2300R10) eşzamansız yürütmeyi yönetmek için standart bir C++ çerçevesi sağlar. Üç temel unsuru vardır: planlayıcılar, gönderenler ve alıcılar ve bir dizi özelleştirilebilir asenkron algoritma sunar.

Proposal P2300R10'un “Merhaba dünya” programı onlara şunları gösteriyor:


using namespace std::execution;

scheduler auto sch = thread_pool.scheduler(); // 1

sender auto begin = schedule(sch); // 2
sender auto hi = then(begin, []{ // 3
std::cout << "Hello world! Have an int."; // 3
return 13; // 3
}); // 3
sender auto add_42 = then(hi, [](int arg) { return arg + 42; }); // 4

auto = this_thread::sync_wait(add_42).value();


Örneğin açıklaması o kadar güzel ki, doğrudan burada alıntılayacağım:

Bu örnekte zamanlayıcılar, gönderenler ve alıcılarla ilgili temel bilgiler gösterilmektedir:

  1. Öncelikle bir yerden, örneğin iş parçacığı havuzundan bir zamanlayıcı almamız gerekiyor. Zamanlayıcı, bir yürütme kaynağına yönelik hafif bir tanıtıcıdır.
  2. Bir zamanlayıcıda bir iş zinciri başlatmak için, zamanlayıcıda tamamlanan göndereni döndüren § 4.19.1execution::schedule'u çağırırız. Gönderici, eşzamansız çalışmayı tanımlar ve iş tamamlandığında bazı alıcılara bir sinyal (değer, hata veya durdurma) gönderir.
  3. Verici üretmek ve asenkron iş oluşturmak için gönderici algoritmalarını kullanıyoruz. § 4.20.2execution::then, bir girdi göndericisini ve bir std::invocable'ı alan ve giriş göndericisi tarafından gönderilen sinyalde std::invocable'ı çağıran bir gönderen bağdaştırıcısıdır. Geri dönen gönderen daha sonra bu çağrının sonucunu gönderir. Bu durumda, giriş göndericisi programdandır, dolayısıyla boştur, yani bize bir değer göndermeyecektir, dolayısıyla std::invocable'ımız hiçbir parametre almaz. Ancak bir sonraki alıcıya gönderilecek olan int'yi döndürüyoruz.
  4. Şimdi yine § 4.20.2execution::then'i kullanarak zincire başka bir işlem ekleyelim. Bu sefer bize bir değer gönderildi: önceki adımdaki int. 42'yi ekleyip sonucu döndürüyoruz.
  5. Son olarak, eşzamansız boru hattının tamamını itmeye ve tamamlanmasını beklemeye hazırız. Bu noktaya kadar her şey tamamen eşzamansızdı; henüz iş başlamamış olabilir. İşin başladığından emin olmak ve tamamlanmasını beklerken engellemek için § 4.21.1 this_thread::sync_wait komutunu kullanırız, bu std::eek:psiyonel değerini döndürür> son gönderen tarafından gönderilen değerle veya son gönderen iptal edilmiş bir sinyal gönderdiyse isteğe bağlı boş bir std::value ile veya son gönderen bir hata gönderdiyse bir istisna atar.
Teklif başka mükemmel örnekler de içeriyor. Gelecek yazılarımda bunları analiz edeceğim.

Okuma-Kopyalama Güncellemesi (RCU) ve Uyarı Göstergeleri


Okuma-Kopyalama Güncellemesi ve Tehlike İşaretçileri, kilitsiz bir yığın gibi kilitsiz veri yapılarının klasik sorununu çözer: diğer iş parçacıkları aynı anda bu düğümü kullanırken bir iş parçacığı bir veri yapısı düğümünü güvenli bir şekilde silebilir mi?

Bu yapılar çok spesifiktir ve bir inceleme makalesinde ele alınamayacak kadar fazla bilgi gerektirir.

Bir sonraki adım nedir?


C++26 ile ilgili bir sonraki makalede odak noktamı değiştirip daha fazla ayrıntıya gireceğim.


(Ben)
 
Üst