Yazılım Geliştirme: C ++ 20'de bir iş parçacığının kooperatif kesintisi

Adanali

Active member
Yazılım Geliştirme: C ++ 20'de bir iş parçacığının kooperatif kesintisi
Bu makale, başlangıçta üç buçuk yıl önce yazdığım bir katkının tekrarlanmasıdır. Bir sonraki makaleye giriş olarak ihtiyacım var. Bu yüzden gönderiyi tekrar yayınlamaya karar verdim.








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.









C ++ 20'de bir iş parçacığının kooperatif kesintisi




Her şeyden önce: Bir konuyu bitirmek neden iyi bir fikir değil? Bu cevap basit. Bitirdiğinizde iş parçacığının hangi durumun olduğunu bilmiyorsunuz. Bunlar iki olası tehlikedir:

  • İplik sadece çalışmasıyla kısmen bitirilebilir. Tabii ki, çalışmasının durumu ve bu nedenle programın durumu bilinmiyor. Sonunda, bu belirsiz davranışa yol açar ve programda güvenilir bir bildirim mümkün değildir.
  • İplik kritik bir alanda bulunabilir ve bir muteks çekmiştir. İplik bu aşamada sona ermişse, bunun bir çıkmaza yol açması muhtemeldir.
Brabidiera bruscily bir iplik iyi bir fikir değildir. İplik dostu, bitirmek isteyip istemediğini sormak daha iyidir. C ++ 20'deki kooperatif kesintisinin tam olarak temsil ettiği şeydir. İplik nazikçe bitmek isteyip istemediğini sorar ve iş parçacığı bu arzuyu tatmin edebilir veya görmezden gelebilir.

Kooperatifi Durdur


C ++ 20'deki kooperatif kesintisinin ek kapasitesi üç yeni veri türüne dayanmaktadır. std::stop_token,, std::stop_callback VE std::stop_source. Bir iş parçacığının eşzamansız bir iş parçacığını bitirmesine veya bir iş parçacığının bir dur işareti alıp almadığını sormasına izin verir. . std::stop_token Bir işleme teslim edilebilir. Bu durak jetonu, operasyona arzunun size gönderilip gönderilmediğini sormak için kullanılabilir. Öte yandan yapabilirsin std::stop_token Kullanarak bir geri arama std::stop_callback kayıt olmak. Tutuklama isteği std::stop_source elçi. İşaretiniz tüm ortaklara çarpıyor std::stop_token. Üç sınıf std::stop_source,, std::stop_token VE std::stop_callback İlişkili tutuklama durumunun mülkü paylaşılırsa. Çağrı request_stop(),, stop_requested() VE stop_possible() Onlar atomiktir.

A std::stop_source İki şekilde üretilebilir:


stop_source(); // (1)
explicit stop_source(std::nostopstate_t) noexcept; // (2)


Varsayılan üretici (1) bir std::stop_source Durma durumu ile. Üretici std::nostopstate_t Bir konu olarak kabul eder, bir tane oluştur std::stop_source İlişkili durma durumu olmadan.

Bileşen std::stop_source src Durdurma istekleriyle başa çıkmak için aşağıdaki yöntemleri sunar:




C ++ 20'de bir iş parçacığının kooperatif kesintisi




src.stop_possible() demek src İlişkili durma durumu vardır. src.stop_requested() O zaman ver true Ne zaman src İlişkili durma durumu vardır ve daha önce talep edilmemiştir. Arama src.get_token() Durdurma jetonunu döndür. Bu sayede, bir tutuklama talebinin zaten gönderilip verilmeyeceği veya yapılabileceği kontrol edilebilir.

Durdurma jetonu stoken Durma kaynağına bakın src. Aşağıdaki tablo, std::stop_token stoken Önce:




C ++ 20'de bir iş parçacığının kooperatif kesintisi




Önceden tanımlanmış inşa edilmiş bir jeton, ilişkili bir tutuklama durumu yoktur. stoken.stop_possible itibaren true geri stoken İlişkili durma durumu vardır. stoken_stop_requested() O zaman ver true Durdurma jetonunun ilişkili bir durum durumu varsa ve tutuklama talebi aldıysa.

Eğer std::stop_token Bazen devre dışı bırakılmalıdır, önceden tanımlanmış bir yapılı jeton ile değiştirilebilir. Bunun ilişkili bir durdurma durumu yoktur. Aşağıdaki satırlar, bir iş parçacığının tutuklama taleplerini alma yeteneğinin geçici olarak nasıl devre dışı bırakılabileceğini göstermektedir:


std::jthread jthr([](std::stop_token stoken) {
...
std::stop_token interruptDisabled;
std::swap(stoken, interruptDisabled); // (1)
... // (2)
std::swap(stoken, interruptDisabled);
...
}


std::stop_token interruptDisabled İlişkili durma durumu yoktur. Bu, iş parçacığının jthr (1) ve (2) durdurma istekleri hariç tüm satırlarda.

Kod parçasını inceleyen herkes dikkatlice düşer std::jthread AÇIK. std::jthread C ++ 20'de genişletilmiş std::thread C ++ 11'den. “J” jthread anlamına gelir birleşikÇünkü bir std::jthread Otomatik olarak muhripine ulaştı. Bu yeni iş parçacığı aslen olarak adlandırıldı ithread: “Ben” anlamına geliyor kesme. Koydum std::jthread Bir sonraki makalede daha kesin.

Bir sonraki örnek nasıl std::jthread Bir geri arama ile kullanılabilir:


// invokeCallback.cpp

#include <chrono>
#include <iostream>
#include <thread>
#include <vector>

using namespace::std::literals;

auto func = [](std::stop_token stoken) { // (1)
int counter{0};
auto thread_id = std::this_thread::get_id();
std::stop_callback callBack(stoken, [&counter, thread_id] // (2)
{
std::cout << "Thread id: " << thread_id
<< "; counter: " << counter << 'n';
});
while (counter < 10) {
std::this_thread::sleep_for(0.2s);
++counter;
}
};

int main() {

std::cout << 'n';

std::vector<std::jthread> vecThreads(10);
for(auto& thr: vecThreads) thr = std::jthread(func);

std::this_thread::sleep_for(1s); // (3)

for(auto& thr: vecThreads) thr.request_stop(); // (4)

std::cout << 'n';

}


On iş parçacığının her biri lambda işlevini çağırıyor func (1) Hon. Geri arama (2) iş parçacığı ve sayaç kimliğini temsil eder. Tek sınıf uykusu sayesinde main-Threads (3) ve çocukların iş parçacığının uykusu, sayaç 4 değerine sahiptir. Geri arama çağrısı sırasında çağrı thr.request_stop() (4) Her iş parçacığında geri arama başlatın.





C ++ 20'de bir iş parçacığının kooperatif kesintisi






(RME)
 
Üst