Boost.Asio çerçevesiyle C++ geliştiricileri, modern C++'da hala yeri olan kanıtlanmış araçlar koleksiyonuna erişebilir. Bağlamlar, uygulayıcılar ve tamamlama belirteçleri ile eşzamansız programları çeşitli ilkelere göre temiz ve verimli bir şekilde geliştirmenize olanak tanır. geri aramalarda vadeli işlemler, spawn VE yield_context aynı zamanda eşyordamlara benzer stillere de izin verirler. Bu, Boost.Asio'nun temellerinin sunulduğu önceki makalede zaten gösterilmiştir.
Duyurudan sonra devamını okuyun
Martin Meeser bağımsız bir bilgisayar bilimcisidir (üniversite) ve yazılım geliştirme alanında hizmetler sunmaktadır: bireysel yazılım geliştirme, süreç danışmanlığı ve eğitim. Otomotiv, finans, uzay yolculuğu, radyo astronomi ve tıbbi teknoloji sektörleri de dahil olmak üzere çok sayıda projede müşterilerine destek vermiştir.
C++20'den itibaren derleyici tabanlı yığınsız eşyordamlar artık mevcuttur. Bununla birlikte Boost.Asio tüm gücünü gösterir. Geliştiriciler, anahtar sözcüklerden herhangi birini kullanarak bir eşyordamdaki herhangi bir işlevi veya yöntemi değiştirebilirler. co_yield, co_await mineral co_return sokmak. Derleyici bu işlevi bir durum makinesine (ortak yordam çerçevesi) dönüştürür ve bu makinenin yürütülmesi co_await VEYA co_yield elipsler işaretlendi ve sonra bir tanesinde std::coroutine_handle devam ediyor. Varsayılan olarak, durumu saklayan eşyordam çerçevesi yığında değil yığında bulunur.
Boost.Asio'da her eşyordamın bir tür örneğine sahip olması gerekir boost::asio::awaitable<T> geri dönmek. awaitable dönüş türünü kapsüller: awaitable<void> dönüş değeri olmayan bir fonksiyon için, awaitable<int> içinde, awaitable<std::string> dize türleri vb. için (Liste 1).
boost::asio::awaitable<void> async_void_sample()
{
co_return;
}
boost::asio::awaitable<int> async_int_sample()
{
co_return 42;
}
boost::asio::awaitable<std::string> async_string_sample()
{
co_return "Hello async";
Liste 1: Geri dönüş türlerini bekleyebilirlikle kapsülleme
Fonksiyon, normal bir program kısmı ile bir ortak rutin kısmı arasında geçiş yapmak için kullanılır. boost::asio::co_spawn. Üç parametre bekliyorsunuz:
- icracı (veya
execution_contextdışarıconvenience) üzerinde eşyordamların aralıklı veya paralel yürütülmesinin gerçekleştiği yer - bir örneği
awaitable<T> - bir CompletionToken türü
detachedişlev nesnesi veyause_future
Duyurudan sonra devamını okuyun
İle detached ırk awaitable sonucu işleyemeden süreç şubenizde. Bu genellikle ana yöntemde başlangıçta bir eşyordamı çağırmak için kullanılır (Liste 2).
int main()
{
boost::asio::io_context io_context;
// co_spawn mit CompletionToken Function-Object
boost::asio::co_spawn(io_context, async_int_sample(), [](std::exception_ptr,
int result)
{
std::cout << "async_int_sample() = " << result << std::endl;
});
// co_spawn mit CompletionToken use_future
std::future future = boost::asio::co_spawn(io_context,
async_string_sample(), boost::asio::use_future);
// co_spawn mit CompletionToken detached
boost::asio::co_spawn(io_context, async_caller(), boost::asio::detached);
io_context.run();
std::string s = future.get();
std::cout << "async_string_sample() = " << s << std::endl;
Liste 2: Bir eşyordamı çağırmak için waitable'ı kullanan Co_spawn örnekleri.
Boost.Asio'da co_await kullanımı
Liste 3 kullanımını gösterir co_await. aradığınızda awaitable ile co_await şunlar olur:
- Bu noktada uygulayıcı eşyordamın yürütülmesini kesebilir. Kesintinin gerçekten gerçekleşip gerçekleşmediği bilinmiyor ve konuyla ilgisiz.
- Yürütücü diğer eylemleri gerçekleştirebilir: tek iş parçacıklı bir bağlamda eşzamanlı olarak veya çok iş parçacıklı bir bağlamda paralel olarak.
- Geliştiricinin bilmediği bir zamanda, uygulayıcı şunları getirir:
awaitablekonularının birindeexecution_contextinfaz için – tam olarak neye dayanarak bilinmiyor ve alakasız.
Bir kez sonucu awaitable mevcut olduğunda, uygulayıcı eşyordama kaldığı yerden devam eder.
boost::asio::awaitable<int> async_callee(int i)
{
std::cout << "hello from awaitable, i=" << i << std::endl;
co_return i + 1;
}
boost::asio::awaitable<void> async_caller()
{
int i = co_await async_callee(1);
// erzeugt ein awaitable, es wird aber nicht ausgeführt
boost::asio::awaitable<int> aw = async_callee(2);
// awaitable kann nicht kopiert werden, move erforderlich
// co_await std::move(aw);
std::cout << "i=" << i << std::endl;
co_return;
}
// Ausgabe:
hello from awaitable, i=1
i=2
Liste 3: co_await'i boost::asio::awaitable ile kullanma örneği.
Bireysel fonksiyon açısından süreç senkronizedir, yani fonksiyon sonuca ulaşana kadar durur. awaitable mevcut. Ancak geliştiricilerin işlevlerini çağırdığı iş parçacığı engellenmez. Konu diğer işbirlikçi eylemler için mevcuttu.
Geliştiriciler şunları yapabilir: awaitable yalnızca bir kez kullanın. Eğer bir awaitable üret ama onunla değil co_await çağrıldığında program işlevi yürütmez.
Liste 3 aynı zamanda nasıl yapılacağını da gösterir co_return tarafından döndürülen değer co_await-ifade awaitable<T>nesne çıkarılır ve çağıran işlevdeki bir değişkene atanır. Bu çok kullanışlı bir mekanizmadır, sonuçta hangi ipliğin olduğu bilinmemektedir. async_callee idama gelir.
Eşyordamlar için iş parçacıkları arası istisna yönetimi
İşlenmeyen istisnalar bir eşyordam içinde meydana gelir, çağıran eşyordamı kabul eder co_await aksine. Eşyordamlar, istisnaların meydana geldiği belirli iş parçacığına bakılmaksızın, senkronize işlevsellik ile aynı şekilde istisnaları yakalar. Liste 4'te kısa bir örnek gösterilmektedir.
#include <boost/asio.hpp>
#include <iostream>
boost::asio::awaitable<void> async_ex_sample()
{
throw std::runtime_error{ "some exception" };
co_return;
}
int main()
{
boost::asio::thread_pool pool(4);
boost::asio::co_spawn(pool, []()->boost::asio::awaitable<void>
{
try
{
co_await async_ex_sample();
}
catch (const std::exception& ex)
{
std::cout << ex.what() << std::endl;
}
co_return;
}, boost::asio::detached);
pool.join();
}
Liste 4: Çapraz İş Parçacığı İstisna İşleme.
Boost-Asio işlevlerini CompletionToken use_awaitable ile kullanma
Liste 5, geliştiricilerin Boost.Asio kütüphanesinin eşzamansız işlevlerini nasıl kullanabileceğini gösterir co_await kullanın: Bunu yapmak için CompletionToken'ı iletin use_awaitable yöntem parametresi olarak async_wait des timer – Nesne, dolayısıyla işlevin döndürdüğü tür artık awaitable.
boost::asio::awaitable<void> async_sample(
boost::asio::steady_timer timer,
boost::asio::ip::tcp::socket socket)
{
co_await timer.async_wait(boost::asio::use_awaitable);
char buf[4096];
std::size_t n = co_await socket.async_read_some(boost::asio::buffer(buf),
boost::asio::use_awaitable);
}
Liste 5: Boost.Asio işlevlerini co_await ve use_awaitablecompleteToken ile kullanma örneği.
Asenkron döngüler
Eşyordamların bir diğer avantajı da döngüleri olağan şekilde ortadan kaldırmalarıdır. for-O while-Stil aynı zamanda eşzamansız süreçler için de formüle edilebilir. Eşyordamlar olmadan yinelemeleri geri aramalara bölmeniz veya daha karmaşık durum makineleri yazmanız gerekir.
Liste 6'daki kod, sonsuz bir döngüdeki bir soketi okur ve alınan verileri doğrudan yeniden yazar: basit bir yankı sunucusu. Kod normal bir döngü gibi görünse de herhangi bir iş parçacığını engellemez. Herkes co_await-expression kontrolü uygulayıcıya döndürür. Veri mevcut olduğunda veya yazma işlemi tamamlandığında döngü kaldığı yerden devam eder – okuma ve yazma işlemlerinin hangi iş parçacığı üzerinde çalıştığı bilinmemektedir – bu, geliştiricinin programda kullandığı yürütücü tarafından belirlenir. co_spawn dedi.
boost::asio::awaitable<void> async_sample(boost::asio::ip::tcp::socket socket)
{
char buf[4096];
for (;;)
{
std::size_t n = co_await socket.async_read_some(
boost::asio::buffer(buf),
boost::asio::use_awaitable);
co_await boost::asio::async_write(
socket,
boost::asio::buffer(buf, n),
boost::asio::use_awaitable);
}
}
Liste 6: Yineleme için eşzamansız örnek.
Hata işleyicileri
Önceki örneklerde gösterildiği gibi eşyordamlarla hata işlemeye yönelik birkaç seçenek vardır:
- hata işleme yok
- yakalamaya çalışmakla
- yerel hata değişkeni
boost::asio::redirect_errortamamlama belirteci olarak - CompletionToken ile bir tanımlama grubundan döndürülen değerin parçası olarak
boost::asio::as_tuple.
Aşağıdaki Liste 7'de ilgili örnekler gösterilmektedir:
boost::asio::awaitable<void> errors_sample(boost::asio::ip::tcp::socket socket)
{
boost::asio::any_io_executor executor = co_await
boost::asio::this_coro::executor;
std::array<char, 4> buffer;
// 1. ohne Fehler-Behandlung
std::size_t n = co_await socket.async_read_some(boost::asio::buffer(buffer),
boost::asio::use_awaitable);
// 2. mit try-catch
try
{
std::size_t bytes_read = co_await
socket.async_read_some(boost::asio::buffer(buffer),
boost::asio::use_awaitable);
}
catch (const boost::system::system_error& e)
{
std::cerr << "Boost error during async_read_some: " << e.what() <<
std::endl;
}
// 3. mit redirect_error CompletionToken
boost::system::error_code ec;
std::size_t bytes_read2 = co_await
socket.async_read_some(boost::asio::buffer(buffer),
boost::asio::redirect_error(boost::asio::use_awaitable, ec));
if (ec)
{
std::cerr << "Error using error_code: " << ec.message() << std::endl;
}
// 4. mit as_tuple CompletionToken
auto [ec2, bytes_read3] = co_await
socket.async_read_some(boost::asio::buffer(buffer),
boost::asio::as_tuple(boost::asio::use_awaitable));
if (ec2)
{
std::cerr << "Error using as_tuple: " << ec2.message() << std::endl;
}
}
Liste 7: Boost.Asio'da farklı hata işleme türlerine örnekler.

Bir yanıt yazın