C++20: Bir iş parçacığını geri aramalarla işbirliği içinde kesme

Adanali

Active member
C++20: Bir iş parçacığını geri aramalarla işbirliği içinde kesme


  1. C++20: Bir iş parçacığını geri aramalarla işbirliği içinde kesme

Hatırlatma olarak, “Yazılım Geliştirme: C++20'de Bir İş Parçacığının İşbirliğine Dayalı Olarak Askıya Alınması” adlı önceki yazımda aşağıdaki programı tanıtmıştım.


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.













// invokeCallback.cpp

#include <chrono>&#13;
#include <iostream>&#13;
#include <thread>&#13;
#include <vector>&#13;
&#13;
using namespace::std::literals;&#13;
&#13;
auto func = [](std::stop_token stoken) { // (1)&#13;
int counter{0};&#13;
auto thread_id = std::this_thread::get_id();&#13;
std::stop_callback callBack(stoken, &#13;
[&counter, thread_id] { // (2)&#13;
std::cout << "Thread id: " << thread_id &#13;
<< "; counter: " << counter << 'n';&#13;
});&#13;
while (counter < 10) {&#13;
std::this_thread::sleep_for(0.2s);&#13;
++counter;&#13;
}&#13;
};&#13;
&#13;
int main() {&#13;
&#13;
std::cout << 'n';&#13;
&#13;
std::vector<std::jthread> vecThreads(10);&#13;
for(auto& thr: vecThreads) thr = std::jthread(func);&#13;
&#13;
std::this_thread::sleep_for(1s); // (3)&#13;
&#13;
for(auto& thr: vecThreads) thr.request_stop(); // (4)&#13;
&#13;
std::cout << 'n';&#13;
&#13;
}


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 sayacı görüntüler. Ana iş parçacığı (3) bir saniye uyuduğundan ve alt iş parçacığı da uyuduğundan, geri aramalar çağrıldığında sayaç 4'tür. Arama thr.request_stop() her iş parçacığında geri aramayı etkinleştirin.








Son yazımda cevabını bulamadığım bir soru:

Geri arama nerede yapılır?


THE std::stop_callbackYapıcı, geri çağırma işlevini kaydeder. std::stop_tokenortak tarafından temsil edilen std::stop_source veriyor. Bu geri çağırma işlevi hem iş parçacığında hem de iş parçacığında çağrılır. request_stop() çağrılarda veya onu çağıran başlıkta std::stop_callback inşa edilmiş. Dosyayı kaydetmeden önce durmanız istenirse std::stop_callback oluşursa, dosyayı içeren iş parçacığında geri arama çağrılır std::stop_callback inşa edilmiş. Aksi takdirde geri arama o iş parçacığında çağrılacaktır. request_stop Aramalar. Çağrı yapıldı request_stop() dosyayı içeren iş parçacığı yürütüldükten sonra std::stop_callback yerleşik olarak kayıtlı geri arama asla çağrılmaz.

Aynı konuyu kullanan bir veya daha fazla iş parçacığı için birden fazla geri arama yapabilirsiniz std::stop_token kaydetmek için. C++ standardı bunların yürütülme sırasına ilişkin hiçbir garanti vermez.

Bir hatırlatmadan daha fazlası



// invokeCallbacks.cpp&#13;
&#13;
#include <chrono>&#13;
#include <iostream>&#13;
#include <thread>&#13;
&#13;
using namespace std::literals;&#13;
&#13;
void func(std::stop_token stopToken) {&#13;
std::this_thread::sleep_for(100ms);&#13;
for (int i = 0; i <= 9; ++i) {&#13;
std::stop_callback cb(stopToken, { std::cout << i; });&#13;
}&#13;
std::cout << 'n';&#13;
}&#13;
&#13;
int main() {&#13;
&#13;
std::cout << 'n';&#13;
&#13;
std::jthread thr1 = std::jthread(func);&#13;
std::jthread thr2 = std::jthread(func);&#13;
thr1.request_stop();&#13;
thr2.request_stop();&#13;
&#13;
std::cout << 'n';&#13;
&#13;
}










Sinyal göndermek için genel bir mekanizma



Çift std::stop_source VE std::stop_token bir sinyal göndermek için genel bir mekanizma olarak görülebilir. Böylece std::stop_token kopyalandığında, sinyali bir şey yapan herhangi bir varlığa gönderebilirsiniz. Aşağıdaki örnekte kullanıyorum std::async, std::promise, std::thread VE std::jthread farklı kombinasyonlarda.


// signalStopRequests.cpp&#13;
&#13;
#include <iostream>&#13;
#include <thread>&#13;
#include <future>&#13;
&#13;
using namespace std::literals;&#13;
&#13;
void function1(std::stop_token stopToken, const std::string& str){&#13;
std::this_thread::sleep_for(1s);&#13;
if (stopToken.stop_requested()) std::cout << str &#13;
<< ": Stop requestedn";&#13;
}&#13;
&#13;
void function2(std::promise<void> prom, &#13;
std::stop_token stopToken, const std::string& str) {&#13;
std::this_thread::sleep_for(1s);&#13;
std::stop_callback callBack(stopToken, [&str] { &#13;
std::cout << str << ": Stop requestedn"; &#13;
});&#13;
prom.set_value();&#13;
}&#13;
&#13;
int main() {&#13;
&#13;
std::cout << 'n';&#13;
&#13;
std::stop_source stopSource; // (1)&#13;
&#13;
std::stop_token stopToken = &#13;
std::stop_token(stopSource.get_token()); // (2)&#13;
&#13;
std::thread thr1 = &#13;
std::thread(function1, stopToken, "std::thread"); // (3)&#13;
&#13;
std::jthread jthr = &#13;
std::jthread(function1, stopToken, "std::jthread"); // (4)&#13;
&#13;
auto fut1 = std::async([stopToken] { // (5)&#13;
std::this_thread::sleep_for(1s);&#13;
if (stopToken.stop_requested()) std::cout &#13;
<< "std::async: Stop requestedn";&#13;
});&#13;
&#13;
std::promise<void> prom; // (6)&#13;
auto fut2 = prom.get_future();&#13;
std::thread thr2(function2, std::move(prom), &#13;
stopToken, "std::promise");&#13;
&#13;
stopSource.request_stop(); // (7)&#13;
if (stopToken.stop_requested()) &#13;
std::cout << "main: Stop requestedn"; // (8)&#13;
&#13;
thr1.join();&#13;
thr2.join();&#13;
&#13;
std::cout << 'n';&#13;
&#13;
}&#13;



sayesinde stopSource (1) Bunu yapabilirim stopToken (2) çalışan her varlık için kullanın, ör. B. std::thread (3), std::jthread (4), std::async (5) veya std::promise (6). A std::stop_token kopyalamak ucuzdur. (7) çözer stopSource.request_stop dıştan. Ayrıca ana kablo (8) sinyali alır. Bu örnekte kullanıyorum std::jthread. std::jthread VE std::condition_variable_any işbirliği kesintilerini daha rahat bir şekilde ele almak için açık üye işlevlerine sahiptir. Daha fazla bilgi “C++20 ile geliştirilmiş bir iş parçacığı” makalesinde bulunabilir.

Sıradaki ne?


Önümüzdeki birkaç hafta boyunca yazmaya ara vereceğim. Bundan sonra C++23 kullanmaya geri döneceğim ve ilk kez C++26 ile devam edeceğim.


(kendim)
 
Üst