Yazılım Geliştirme: Dian-Lun Li Choroutins'e Kompakt Giriş
Bugün blogumda bir görev zamanlayıcısında bir mini diziye başlıyorum. Bu mini dizinin başlangıç noktası, gittikçe daha sofistike hale gelen basit bir Dian-Lun Li programıdır.
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.
Zaten koroda yaklaşık 15 makale yazdım. Koro teorisini açıklarlar ve farklı şekillerde uygularlar. Ama hala koronun önemsiz bir uygulamasına sezgisel bir giriş için savaşıyorum. Bu yüzden CPPCCC 2022'de Dian-Lun Li dersini duyduğumda çok mutlu oldum: “C ++ korosunu bir iplik planlama gösterisi ile tanıtmak”.
Bugün Dian-Lun Li'den bir konuk makale tanıtabildiğim için mutluyum. Etkinlikleri dağıtan basit bir program uygulamak için choutinleri sezgisel olarak anlayacaktır. Bu zamanlayıcı daha fazla deney için bir başlangıç noktası olarak kullanacağım.
C ++ koririne giriş
Koro, onu kesintiye uğratabilen ve arayan tarafından alınabilen bir işlevdir. Başlangıçtan sonuna kadar sırayla gerçekleştirilen normal işlevlerin aksine, koro yürütmeyi kontrollü bir şekilde durdurabilir ve devam edebilir. Böylece senkronize görünen bir kod yazabiliriz, ancak çağrı iş parçacığını engellemeden asenkron işlemleri verimli bir şekilde işleyebiliriz. Bir C ++ choroutine uygulanması, çok yönlülüğü nedeniyle küçük bir zorluk olabilir. C ++ korosunda, bir koronun davranışı çok sayıda türde ince bir şekilde koordine edilebilir. Örneğin, başladığınızda veya bittiğinizde bir bakıcının kesintiye uğraması gerekip gerekmediğine karar verebilirsiniz. Ancak, bu kesintilerin koro içinde ne zaman ve nerede olduğunu tam olarak belirleyebilirsiniz. Bir örnek olarak, basit bir örnekle başlamak istiyorum:
// simpleCoroutine.cpp
#include <coroutine>
#include <iostream>
struct MyCoroutine { // (1)
struct promise_type {
MyCoroutine get_return_object() {
return std::coroutine_handle<promise_type>::from_promise(*this);
}
std::suspend_always initial_suspend() {
return {};
}
std::suspend_always final_suspend() noexcept {
return {};
}
void return_void() {}
void unhandled_exception() {}
};
MyCoroutine(std::coroutine_handle<promise_type> handle): handle{handle} {}
void resume() {
handle.resume();
}
void destroy() {
handle.destroy();
}
std::coroutine_handle<promise_type> handle;
};
MyCoroutine simpleCoroutine() { // (2)
std::cout << "Start coroutinen";
co_await std::suspend_always{};
std::cout << "Resume coroutinen";
}
int main() {
MyCoroutine coro = simpleCoroutine();
std::cout << "Coroutine is not executed yetn";
coro.resume();
std::cout << "Suspend coroutinen";
coro.resume();
coro.destroy();
return 0;
}
Bu örnek kod, C ++ korosunun temel kullanımını gösterir. Uygulama için, dört temel bileşen dahil etmek gerekir: choroutines, ünlü türü, bekleme ve choroutine kolu. Aşağıdaki bölümlerde her bir bileşeni örnek koduna göre açıklayacağım.
Choroutin
C ++ 'da, koro anahtar kelimelerle yapılır co_return,, co_await VE co_yield uygulandı. Bu anahtar kelimeler, geliştiricilerin asenkron davranışı yapılandırılmış ve sezgisel bir şekilde ifade etmelerini sağlar. CHOROUTINE örneğinde simpleCoroutine Arama co_await std::suspend always{} Koroyu durdurmak için. std::suspend_always Her zaman koroyu askıya alan C ++ standardı tarafından sağlanan bir beklemedir.
İşlevi çağırırken simpleCoroutineKoro hemen gerçekleştirilmez. Bunun yerine, ünlü türünü tanımlayan bir kodedouutin nesnesi döndürürsünüz. (2) işlevi tanımlar simpleCoroutineBir MyCoroutine-Plet geri döner. (1) içinde sınıfı tanımlıyorum MyCoroutine Ve ünlü türü. Bir Corover fonksiyonuna çağrının hemen gerçekleştirmemesi, C ++ korosunun esnek olması gerektiğidir. C ++ korosu ile bir koronun ne zaman ve nasıl başlaması ve bitmesi gerektiğine karar verebilirsiniz. Bu im promise_type tanımlanmış.
Ünlü türü
A promise_type Bir koronun davranışını kontrol edin. İşte en önemli görevler promise_type:
MyCoroutine simpleCoroutine() {
MyCoroutine:
romise_type p();
MyCoroutine coro_obj = p.get_return_object();
try {
co_await p.inital_suspend();
std::cout << "Start coroutinen";
co_await std::suspend_always{};
std::cout << "Resume coroutinen";
} catch(...) {
p.unhandled_exception();
}
co_await p.final_suspend();
}
Bu nedenle olmalı promise_type sınıfta MyCoroutine tanımlanmalıdır. Eğer simpleCoroutine Derleyici bir tane oluşturur promise_type ve çağrı get_return_object() bunu yapmak MyCoroutine-nesne oluşturmak için. Derleyici, koronun gövdesinin önünde çağırıyor initial_suspend Koronun başlangıçta durdurulup durdurulmayacağını belirlemek için. Sonunda çağrılar final_suspend Sonunda yürütmenin kesintiye uğraması gerekip gerekmediğini belirlemek için. DSÖ promise_type Ve karşılık gelen işlevler tanımlanmamıştır, derleyicinin bir hatası alır.
Askıda olması
Dikkatli bir süspansiyon noktasının davranışını kontrol eder. Beklemek için üç işlev tanımlanmalıdır:
auto&& awaiter = std::suspend_always{};
if(!awaiter.await_ready()) {
awaiter.await_suspend(std::coroutine_handle<>...);
//<suspend/resume>
}
awaiter.await_resume();
Bu nedenle, tüm bu işlevleri tanımlamanız gerekir. . std::suspend_always C ++ 'da işlevleri aşağıdaki gibi tanımlayan entegre bir beklentidir:
struct suspend_always {
constexpr bool await_ready() const noexcept { return false; }
constexpr void await_suspend(coroutine_handle<>) const noexcept {}
constexpr void await_resume() const noexcept {}
};
Choroutin kolu
Koro kolları, bir koroutin durumunu ve yaşam döngüsünü yönetmek için kullanılır. Koroyu açıkça aramak, devam etmek ve yok etmek için bir yol sunarlar. Örnekte arıyorum handle.resume() Koroya devam etmek için handle.destroy()koroyu yok etmek.
Programın yürütülmesinin sonucu şu gibi görünüyor:
Sırada ne var?
Söz verildiği gibi, Dian-Lun'un bu makalesi koroya kompakt bir girişti. Bir sonraki makalede, Dian-Lun teoriyi C ++ korosu için tek bir iş parçacığı programı uygulamak için kullanıyor.
Programlama Modern C ++ Eğitimi
(RME)
Yazılım Geliştirme: Dian-Lun Li Choroutins'e Kompakt Giriş
Bugün blogumda bir görev zamanlayıcısında bir mini diziye başlıyorum. Bu mini dizinin başlangıç noktası, gittikçe daha sofistike hale gelen basit bir Dian-Lun Li programıdır.

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.

Zaten koroda yaklaşık 15 makale yazdım. Koro teorisini açıklarlar ve farklı şekillerde uygularlar. Ama hala koronun önemsiz bir uygulamasına sezgisel bir giriş için savaşıyorum. Bu yüzden CPPCCC 2022'de Dian-Lun Li dersini duyduğumda çok mutlu oldum: “C ++ korosunu bir iplik planlama gösterisi ile tanıtmak”.
Bugün Dian-Lun Li'den bir konuk makale tanıtabildiğim için mutluyum. Etkinlikleri dağıtan basit bir program uygulamak için choutinleri sezgisel olarak anlayacaktır. Bu zamanlayıcı daha fazla deney için bir başlangıç noktası olarak kullanacağım.
C ++ koririne giriş
Koro, onu kesintiye uğratabilen ve arayan tarafından alınabilen bir işlevdir. Başlangıçtan sonuna kadar sırayla gerçekleştirilen normal işlevlerin aksine, koro yürütmeyi kontrollü bir şekilde durdurabilir ve devam edebilir. Böylece senkronize görünen bir kod yazabiliriz, ancak çağrı iş parçacığını engellemeden asenkron işlemleri verimli bir şekilde işleyebiliriz. Bir C ++ choroutine uygulanması, çok yönlülüğü nedeniyle küçük bir zorluk olabilir. C ++ korosunda, bir koronun davranışı çok sayıda türde ince bir şekilde koordine edilebilir. Örneğin, başladığınızda veya bittiğinizde bir bakıcının kesintiye uğraması gerekip gerekmediğine karar verebilirsiniz. Ancak, bu kesintilerin koro içinde ne zaman ve nerede olduğunu tam olarak belirleyebilirsiniz. Bir örnek olarak, basit bir örnekle başlamak istiyorum:
// simpleCoroutine.cpp
#include <coroutine>
#include <iostream>
struct MyCoroutine { // (1)
struct promise_type {
MyCoroutine get_return_object() {
return std::coroutine_handle<promise_type>::from_promise(*this);
}
std::suspend_always initial_suspend() {
return {};
}
std::suspend_always final_suspend() noexcept {
return {};
}
void return_void() {}
void unhandled_exception() {}
};
MyCoroutine(std::coroutine_handle<promise_type> handle): handle{handle} {}
void resume() {
handle.resume();
}
void destroy() {
handle.destroy();
}
std::coroutine_handle<promise_type> handle;
};
MyCoroutine simpleCoroutine() { // (2)
std::cout << "Start coroutinen";
co_await std::suspend_always{};
std::cout << "Resume coroutinen";
}
int main() {
MyCoroutine coro = simpleCoroutine();
std::cout << "Coroutine is not executed yetn";
coro.resume();
std::cout << "Suspend coroutinen";
coro.resume();
coro.destroy();
return 0;
}
Bu örnek kod, C ++ korosunun temel kullanımını gösterir. Uygulama için, dört temel bileşen dahil etmek gerekir: choroutines, ünlü türü, bekleme ve choroutine kolu. Aşağıdaki bölümlerde her bir bileşeni örnek koduna göre açıklayacağım.
Choroutin
C ++ 'da, koro anahtar kelimelerle yapılır co_return,, co_await VE co_yield uygulandı. Bu anahtar kelimeler, geliştiricilerin asenkron davranışı yapılandırılmış ve sezgisel bir şekilde ifade etmelerini sağlar. CHOROUTINE örneğinde simpleCoroutine Arama co_await std::suspend always{} Koroyu durdurmak için. std::suspend_always Her zaman koroyu askıya alan C ++ standardı tarafından sağlanan bir beklemedir.
İşlevi çağırırken simpleCoroutineKoro hemen gerçekleştirilmez. Bunun yerine, ünlü türünü tanımlayan bir kodedouutin nesnesi döndürürsünüz. (2) işlevi tanımlar simpleCoroutineBir MyCoroutine-Plet geri döner. (1) içinde sınıfı tanımlıyorum MyCoroutine Ve ünlü türü. Bir Corover fonksiyonuna çağrının hemen gerçekleştirmemesi, C ++ korosunun esnek olması gerektiğidir. C ++ korosu ile bir koronun ne zaman ve nasıl başlaması ve bitmesi gerektiğine karar verebilirsiniz. Bu im promise_type tanımlanmış.
Ünlü türü
A promise_type Bir koronun davranışını kontrol edin. İşte en önemli görevler promise_type:
- Choroutine nesnesinin oluşturulması: işlev get_return_object Koronun bir örneğini oluşturun ve arayana döndürür.
- Süspansiyon kontrolü: işlevler initial_suspend VE final_suspend Koronun başlangıçta ve sonunda kesintiye uğraması veya devam etmesi gerekip gerekmediğini belirler. Koronun nasıl davrandığını belirlemelerini beklerken geri dönerler.
- Dönüş değerleriyle yüz: işlev return_value Sonunda koronun dönüş değerini algılar. Koronun arayanın hatırlayabileceği bir sonuç vermesini sağlar. Örnek kodda kullanın return_voidBu bakıcının iade değeri olmadığını belirtmek için.
- İstisnaların tedavisi: işlev unhandled_exception Koronun içinde ilgisiz bir istisna oluştuğunda denir. İstisnaları zarif bir şekilde tedavi etmek için bir mekanizma sunar.
MyCoroutine simpleCoroutine() {
MyCoroutine:
MyCoroutine coro_obj = p.get_return_object();
try {
co_await p.inital_suspend();
std::cout << "Start coroutinen";
co_await std::suspend_always{};
std::cout << "Resume coroutinen";
} catch(...) {
p.unhandled_exception();
}
co_await p.final_suspend();
}
Bu nedenle olmalı promise_type sınıfta MyCoroutine tanımlanmalıdır. Eğer simpleCoroutine Derleyici bir tane oluşturur promise_type ve çağrı get_return_object() bunu yapmak MyCoroutine-nesne oluşturmak için. Derleyici, koronun gövdesinin önünde çağırıyor initial_suspend Koronun başlangıçta durdurulup durdurulmayacağını belirlemek için. Sonunda çağrılar final_suspend Sonunda yürütmenin kesintiye uğraması gerekip gerekmediğini belirlemek için. DSÖ promise_type Ve karşılık gelen işlevler tanımlanmamıştır, derleyicinin bir hatası alır.
Askıda olması
Dikkatli bir süspansiyon noktasının davranışını kontrol eder. Beklemek için üç işlev tanımlanmalıdır:
- await_ready: Bu işlev, koronun kesintisiz devam edip edemeyeceğini belirler. Zorunlu true İşlem hemen devam edebilirse veya falseBir kesinti gerekiyorsa. Bu yöntem, sürecin eşzamanlı olarak tamamlanacağı bilinen durumlarda kesintinin maliyetlerinden kaçınmanın mümkün olduğu bir optimizasyondur.
- await_suspend: Bu işlevle bir süspansiyon noktasının davranışını doğru bir şekilde kontrol edebilirsiniz. Kullanıcıların koroya daha sonra devam edebilmesi veya yok edebilmesi için mevcut koroutin tutamağının üstünde teslim edilir. Bu işlev için üç tür getiri vardır:
- boş: Koroyu açığa çıkarıyoruz. Kontrol derhal mevcut koronun arayanına iade edilir.
- bool:: A true Mevcut koroyu kesintiye uğratırsak ve kontrolü arayana iade edersek; İLE false Mevcut bakıcıya devam ediyoruz.
- coroutine_handle: Mevcut koroyu durduruyoruz ve iade edilen koroutin kolunu emiyoruz. Bu aynı zamanda bir asimer transferi olarak da tanımlanır.
- await_resume: Bu işlev, beklenen işlem tamamlanırsa hangi değerin koroya döndürülmesi gerektiğini gösterir. Choutine'nin yürütülmesi devam eder ve beklenen sonuçta eller devam eder. Hiçbir veya gerekli sonuç gerekmiyorsa, bu işlev boş olabilir ve void geri dönmek.
auto&& awaiter = std::suspend_always{};
if(!awaiter.await_ready()) {
awaiter.await_suspend(std::coroutine_handle<>...);
//<suspend/resume>
}
awaiter.await_resume();
Bu nedenle, tüm bu işlevleri tanımlamanız gerekir. . std::suspend_always C ++ 'da işlevleri aşağıdaki gibi tanımlayan entegre bir beklentidir:
struct suspend_always {
constexpr bool await_ready() const noexcept { return false; }
constexpr void await_suspend(coroutine_handle<>) const noexcept {}
constexpr void await_resume() const noexcept {}
};
Choroutin kolu
Koro kolları, bir koroutin durumunu ve yaşam döngüsünü yönetmek için kullanılır. Koroyu açıkça aramak, devam etmek ve yok etmek için bir yol sunarlar. Örnekte arıyorum handle.resume() Koroya devam etmek için handle.destroy()koroyu yok etmek.
Programın yürütülmesinin sonucu şu gibi görünüyor:

Sırada ne var?
Söz verildiği gibi, Dian-Lun'un bu makalesi koroya kompakt bir girişti. Bir sonraki makalede, Dian-Lun teoriyi C ++ korosu için tek bir iş parçacığı programı uygulamak için kullanıyor.
Programlama Modern C ++ Eğitimi
(RME)