C ++ 20: Geri arama ile bir iş parçacığının kooperatif kesintisi
Bir hatırlatma olarak: önceki makalemde “Yazılım Geliştirme: C ++ 20'de bir iş parçacığının işbirliği kesintisi” aşağıdaki programı sundum.
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.
// 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) kimlik iş parçacığını ve sayaçını gösterir. Ana iş parçacığı (3) bir saniye ve alt iplikler uyuduğundan, 4 sayaç geri çağrıların çağrıldığı zamandır. Arama thr.request_stop() Deralark her iş parçacığındaki geri çağrıda.
Son makalemde bir soru cevaplanmadı:
Geri arama nerede gerçekleştirildi?
. std::stop_callback-Codor, geri arama işlevini kaydeder. std::stop_tokenBu iştirak aracılığıyla std::stop_source Verilir. Bu geri arama işlevi, request_stop() arayın veya iş parçacığında std::stop_callback inşa edildi. Tutuklama talebi kaydetmeden önce std::stop_callback Geri arama, iş parçacığında çağrılırsa std::stop_callback inşa edildi. Aksi takdirde geri arama, iş parçacığında çağrılır, request_stop çağrılar. Çağrı çağrılırsa request_stop() İpliği gerçekleştirdikten sonra, std::stop_callback Yapılan, kaydedilen geri arama asla çağrılmaz.
Aynı ile bir veya daha fazla iş parçacığı için birden fazla geri arama yapabilirsiniz std::stop_token kayıt olmak. C ++ standardı, gerçekleştirildikleri sipariş için herhangi bir garanti sunmaz.
Bir Geri Aramadan Daha Fazlası
// invokeCallbacks.cpp
#include <chrono>
#include <iostream>
#include <thread>
using namespace std::literals;
void func(std::stop_token stopToken) {
std::this_thread::sleep_for(100ms);
for (int i = 0; i <= 9; ++i) {
std::stop_callback cb(stopToken, { std::cout << i; });
}
std::cout << 'n';
}
int main() {
std::cout << 'n';
std::jthread thr1 = std::jthread(func);
std::jthread thr2 = std::jthread(func);
thr1.request_stop();
thr2.request_stop();
std::cout << 'n';
}
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. Birinden std::stop_token Kopyalı, sinyali bir şey yapan herhangi bir varlığa gönderebilirsiniz. Aşağıdaki örnekte kullanıyorum std::async, std:
romise, std::thread VE std::jthread farklı kombinasyonlarda.
// signalStopRequests.cpp
#include <iostream>
#include <thread>
#include <future>
using namespace std::literals;
void function1(std::stop_token stopToken, const std::string& str){
std::this_thread::sleep_for(1s);
if (stopToken.stop_requested()) std::cout << str
<< ": Stop requestedn";
}
void function2(std:
romise<void> prom,
std::stop_token stopToken, const std::string& str) {
std::this_thread::sleep_for(1s);
std::stop_callback callBack(stopToken, [&str] {
std::cout << str << ": Stop requestedn";
});
prom.set_value();
}
int main() {
std::cout << 'n';
std::stop_source stopSource; // (1)
std::stop_token stopToken =
std::stop_token(stopSource.get_token()); // (2)
std::thread thr1 =
std::thread(function1, stopToken, "std::thread"); // (3)
std::jthread jthr =
std::jthread(function1, stopToken, "std::jthread"); // (4)
auto fut1 = std::async([stopToken] { // (5)
std::this_thread::sleep_for(1s);
if (stopToken.stop_requested()) std::cout
<< "std::async: Stop requestedn";
});
std:
romise<void> prom; // (6)
auto fut2 = prom.get_future();
std::thread thr2(function2, std::move(prom),
stopToken, "std:
romise");
stopSource.request_stop(); // (7)
if (stopToken.stop_requested())
std::cout << "main: Stop requestedn"; // (8)
thr1.join();
thr2.join();
std::cout << 'n';
}
Sayesinde stopSource (1) Yapabilirim stopToken (2) Her mevcut varlık için kullanım, ör. B. std::thread (3), std :: jthread (4), std :: async (5) veya std:
romise (6). A std::stop_token Kopyalamak ucuz. (7) Çöz stopSource.request_stop dışında. Ana iş parçacığı (8) ayrıca sinyali alır. Bu örnekte kullanın std::jthread. std::jthread VE std::condition_variable_any Kooperatif kesintilerle daha uygun bir şekilde karşılaşabilmek için üyelerin açık işlevleri vardır. Diğer “C ++ 20 ile geliştirilmiş bir iş parçacığı” makalesinde.
Sırada ne var?
Önümüzdeki iki hafta içinde yazmayı ara vereceğim. Bu yüzden C ++ 23'e geri döneceğim ve ilk kez 26 ekleyeceğim.
(RME)
C ++ 20: Geri arama ile bir iş parçacığının kooperatif kesintisi
Bir hatırlatma olarak: önceki makalemde “Yazılım Geliştirme: C ++ 20'de bir iş parçacığının işbirliği kesintisi” aşağıdaki programı sundum.

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.

// 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) kimlik iş parçacığını ve sayaçını gösterir. Ana iş parçacığı (3) bir saniye ve alt iplikler uyuduğundan, 4 sayaç geri çağrıların çağrıldığı zamandır. Arama thr.request_stop() Deralark her iş parçacığındaki geri çağrıda.

Son makalemde bir soru cevaplanmadı:
Geri arama nerede gerçekleştirildi?
. std::stop_callback-Codor, geri arama işlevini kaydeder. std::stop_tokenBu iştirak aracılığıyla std::stop_source Verilir. Bu geri arama işlevi, request_stop() arayın veya iş parçacığında std::stop_callback inşa edildi. Tutuklama talebi kaydetmeden önce std::stop_callback Geri arama, iş parçacığında çağrılırsa std::stop_callback inşa edildi. Aksi takdirde geri arama, iş parçacığında çağrılır, request_stop çağrılar. Çağrı çağrılırsa request_stop() İpliği gerçekleştirdikten sonra, std::stop_callback Yapılan, kaydedilen geri arama asla çağrılmaz.
Aynı ile bir veya daha fazla iş parçacığı için birden fazla geri arama yapabilirsiniz std::stop_token kayıt olmak. C ++ standardı, gerçekleştirildikleri sipariş için herhangi bir garanti sunmaz.
Bir Geri Aramadan Daha Fazlası
// invokeCallbacks.cpp
#include <chrono>
#include <iostream>
#include <thread>
using namespace std::literals;
void func(std::stop_token stopToken) {
std::this_thread::sleep_for(100ms);
for (int i = 0; i <= 9; ++i) {
std::stop_callback cb(stopToken, { std::cout << i; });
}
std::cout << 'n';
}
int main() {
std::cout << 'n';
std::jthread thr1 = std::jthread(func);
std::jthread thr2 = std::jthread(func);
thr1.request_stop();
thr2.request_stop();
std::cout << 'n';
}

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. Birinden std::stop_token Kopyalı, sinyali bir şey yapan herhangi bir varlığa gönderebilirsiniz. Aşağıdaki örnekte kullanıyorum std::async, std:
// signalStopRequests.cpp
#include <iostream>
#include <thread>
#include <future>
using namespace std::literals;
void function1(std::stop_token stopToken, const std::string& str){
std::this_thread::sleep_for(1s);
if (stopToken.stop_requested()) std::cout << str
<< ": Stop requestedn";
}
void function2(std:
std::stop_token stopToken, const std::string& str) {
std::this_thread::sleep_for(1s);
std::stop_callback callBack(stopToken, [&str] {
std::cout << str << ": Stop requestedn";
});
prom.set_value();
}
int main() {
std::cout << 'n';
std::stop_source stopSource; // (1)
std::stop_token stopToken =
std::stop_token(stopSource.get_token()); // (2)
std::thread thr1 =
std::thread(function1, stopToken, "std::thread"); // (3)
std::jthread jthr =
std::jthread(function1, stopToken, "std::jthread"); // (4)
auto fut1 = std::async([stopToken] { // (5)
std::this_thread::sleep_for(1s);
if (stopToken.stop_requested()) std::cout
<< "std::async: Stop requestedn";
});
std:
auto fut2 = prom.get_future();
std::thread thr2(function2, std::move(prom),
stopToken, "std:
stopSource.request_stop(); // (7)
if (stopToken.stop_requested())
std::cout << "main: Stop requestedn"; // (8)
thr1.join();
thr2.join();
std::cout << 'n';
}
Sayesinde stopSource (1) Yapabilirim stopToken (2) Her mevcut varlık için kullanım, ör. B. std::thread (3), std :: jthread (4), std :: async (5) veya std:
Sırada ne var?
Önümüzdeki iki hafta içinde yazmayı ara vereceğim. Bu yüzden C ++ 23'e geri döneceğim ve ilk kez 26 ekleyeceğim.
(RME)