Yazılım Mühendisliği: C++20'de Bir İş Parçacığının İşbirliğine Dayalı Askıya Alınması

Adanali

Active member
Yazılım Mühendisliği: C++20'de Bir İş Parçacığının İşbirliğine Dayalı Askıya Alınması
Bu makale, üç buçuk yıl önce yazdığım bir yazının tekrarıdır. Bir sonraki makale için başlangıç noktası olarak buna ihtiyacım var. Bu nedenle yazıyı tekrar yayınlamaya karar verdim.


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.









C++20'de bir iş parçacığını ortaklaşa askıya alma




Öncelikle konuyu kapatmak neden iyi bir fikir değil? Bu cevap basit. Konuyu sonlandırdığınızda iş parçacığının ne durumda olduğunu bilemezsiniz. Bunlar iki olası tehlikedir:

  • İş parçacığı işini yalnızca kısmen tamamlamış olabilir. Tabii ki, çalışmalarının ve dolayısıyla programın durumu şu anda bilinmiyor. Sonuçta bu, tanımsız davranışa yol açar ve artık program hakkında güvenilir beyanların yapılması mümkün değildir.
  • İş parçacığı şu anda kritik bir alanda olabilir ve kilitli bir mutekse sahip olabilir. İş parçacığı bu aşamada sona ererse, büyük olasılıkla bir kilitlenmeye yol açacaktır.
Bir konuyu aniden sonlandırmak iyi bir fikir değildir. Konuyu kapatmak istiyorsanız kibarca sormak en iyisidir. İşbirlikçi kırmanın C++20'de temsil ettiği şey tam olarak budur. Konunun bitmek isteyip istemediğini kibarca sorun; konu isteğinizi yerine getirebilir veya görmezden gelebilir.

İşbirliğinin sona ermesi


C++20'deki ek işbirlikçi kesme işlevi üç yeni veri türüne dayanmaktadır std::stop_token, std::stop_callback VE std::stop_source. Bir iş parçacığının bir iş parçacığını eşzamansız olarak sonlandırmasına veya bir iş parçacığının bir durdurma sinyali alıp almadığını sormasına izin verirler. THE std::stop_token bu amaçla bir operasyona teslim edilebilirler. Bu durdurma belirteci daha sonra işleme bir sonlandırma isteğinin gönderilip gönderilmediğini sormak için kullanılabilir. Öte yandan şunları yapabilirsiniz: std::stop_token kullanarak bir geri arama std::stop_callback kaydetmek için. Durdurma isteği şu kişi tarafından yapılır: std::stop_source elçi. Sinyaliniz tüm çalışanları etkiliyor std::stop_token. Üç sınıf std::stop_source, std::stop_token VE std::stop_callback ilgili kapatma durumunun sahipliğini paylaşın. çağrılar request_stop(), stop_requested() VE stop_possible() onlar atomiktir.

A std::stop_source iki şekilde oluşturulabilir:


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


Varsayılan yapıcı (1) bir oluşturur std::stop_source Tutukluluk durumuyla. İnşaatçı, std::nostopstate_t argümanın ürettiği gibi alır std::stop_source ilişkili durma durumu olmadan.

Bileşen std::stop_source src durdurma isteklerini işlemek için aşağıdaki yöntemleri sunar:




C++20'de bir iş parçacığını ortaklaşa askıya alma




src.stop_possible() anlamına gelir src ilişkili bir durma durumuna sahiptir. src.stop_requested() sonra verir true eğer geri dön src ilişkili bir tutuklama statüsüne sahiptir ve daha önce durdurulması talep edilmemiştir. Arama src.get_token() kapatma belirtecini döndürür. Bu sayede bir durdurma talebinin daha önce yapılıp yapılmadığını veya gerçekleştirilip gerçekleştirilemeyeceğini kontrol etmek mümkündür.

Durdurma jetonu stoken durdurma kaynağını gözlemleyin src. Aşağıdaki tabloda yöntemler sunulmaktadır std::stop_token stoken Önce:




C++20'de bir iş parçacığını ortaklaşa askıya alma




Varsayılan olarak oluşturulan bir belirtecin kendisiyle ilişkilendirilmiş bir kapatma durumu yoktur. stoken.stop_possible itibaren true eğer geri dön stoken ilişkili bir durma durumuna sahiptir. stoken_stop_requested() sonra verir true kapatma belirtecinin bir kapatma durumuna sahip olup olmadığını ve zaten bir kapatma isteği alıp almadığını döndürür.

Eğer std::stop_token Geçici olarak devre dışı bırakmak isterseniz varsayılan olarak oluşturulmuş bir jetonla değiştirilebilir. Bunun kendisiyle ilişkilendirilmiş bir durma durumu yoktur. Aşağıdaki satırlar, bir iş parçacığının kesme isteklerini alma yeteneğinin geçici olarak nasıl devre dışı bırakılacağını gösterir:


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 ilişkili bir durma durumu yoktur. Bu, iplik anlamına gelir jthr (1) ve (2) dışındaki tüm hatlardaki durdurma isteklerini kabul edebilir.

Kod pasajını dikkatlice incelerseniz sorun yaşamazsınız std::jthread AÇIK. std::jthread C++20'de genişletildi std::thread C++11'den. İçindeki “j” jthread anlamına gelir birleştirilebilirneden bir std::jthread yıkıcısında otomatik olarak birleştirilir. Bu yeni konunun orijinal adı ithread: “i” anlamına gelir kesilebilir. Koydum std::jthread bir sonraki makalede daha ayrıntılı bilgi vereceğiz.

Bir sonraki örnek nasıl olduğunu gösteriyor std::jthread geri aramayla birlikte 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ır func (1 Yukarı. Geri arama (2), iş parçacığı kimliğini ve bir saniyelik uyku sayacı sayesinde mainiş parçacığı (3) ve alt iş parçacıkları duraklatılır, geri arama sırasında sayaç 4 değerine sahiptir thr.request_stop() (4) her iş parçacığında geri aramayı başlatın.





C++20'de bir iş parçacığını ortaklaşa askıya alma






(kendim)
 
Üst