C ++ Programlama Dili: Koro için zorlu bir öncelik zamanlayıcı
Bu, C ++ Coroutinen için zamanlayıcı ile ilgili mini serimin dördüncü makalesi. İlk iki makale Dian-Lun Lin'in konuklarının gönderileriydi:
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.
Dian-Luns'un zamanlayıcısı konteyner adaptörüne dayanıyordu std::stack VE std::queue. . std::stack İlk çıkış stratejisinden sonra görevlerini dikin, ancak std::queue Sırtta birincisini kullanın. Sonunda benimkini destekliyor std:
riority_queue-Scille son makaleden alınmıştır. Görevlerin önceliklerinin tanımı.
Bu makalede en son programı iki şekilde geliştireceğim. Her şeyden önce, karşılaştırma işlevini kullanmak istiyorum. std:
riority_queue oynamak.
Karşılaştırma işlevi
Öncelik kuyruğu her zaman en büyük unsuruna sahiptir. std:
riority_queue Varsayılan olarak karşılaştırma operatörünü kullanmak std::less. Aşağıdaki zamanlayıcı bir model parametresi olarak karşılaştırma işlevine sahiptir.
// priority_queueSchedulerComparator.cpp
#include <concepts>
#include <coroutine>
#include <functional>
#include <iostream>
#include <queue>
#include <utility>
struct Task {
struct promise_type {
std::suspend_always initial_suspend() noexcept { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
Task get_return_object() {
return std::coroutine_handle<promise_type>::from_promise(*this);
}
void return_void() {}
void unhandled_exception() {}
};
Task(std::coroutine_handle<promise_type> handle): handle{handle}{}
auto get_handle() { return handle; }
std::coroutine_handle<promise_type> handle;
};
using job = std:
air<int, std::coroutine_handle<>>; // (1)
template <typename Comparator = std::ranges::less> // (2)
requires std:
redicate<decltype(Comparator()), job, job> // (3)
class Scheduler {
std:
riority_queue<job, std::vector<job>, Comparator> _prioTasks;
public:
void emplace(int prio, std::coroutine_handle<> task) {
_prioTasks.push(std::make_pair(prio, task));
}
void schedule() {
while(!_prioTasks.empty()) {
auto [prio, task] = _prioTasks.top();
_prioTasks.pop();
task.resume();
if(!task.done()) {
_prioTasks.push(std::make_pair(prio, task)); // (6)
}
else {
task.destroy();
}
}
}
};
Task createTask(const std::string& name) {
std::cout << name << " startn";
co_await std::suspend_always();
std::cout << name << " executen";
co_await std::suspend_always();
std::cout << name << " finishn";
}
int main() {
std::cout << 'n';
Scheduler scheduler1; // (4)
scheduler1.emplace(0, createTask("TaskA").get_handle());
scheduler1.emplace(1, createTask(" TaskB").get_handle());
scheduler1.schedule();
std::cout << 'n';
Scheduler<std::ranges::greater> scheduler2; // (5)
scheduler2.emplace(0, createTask("TaskA").get_handle());
scheduler2.emplace(1, createTask(" TaskB").get_handle());
scheduler2.schedule();
std::cout << 'n';
}
Zamanlayıcıyı ezenler dizinin önceki makalesini okumalıdır. Her şeyden önce, bir öncelik ve bir aktivite kombinasyonu diyorum (1). Zamanlayıcının bir model parametresine ihtiyacı var ComparatorVarsayılan değer std::ranges::less (2). Konsept de kontrol ediyor std::
redicate (3) 'de, yüklem iki eserle hatırlanabilirse.
scheduler1 (5) en üst düzey önceliğe göre çalışmaya başlar, scheduler2 (6) Öte yandan, en düşük önceliğe sahip çalışmalarla.
(6) 'da çalışmamı zamanlayıcı üzerine koydum. Görevlendirilen bir emrin önceliğini değiştirebilseydim iyi olmaz mıydı?
Önceliği Güncelle
Aşağıdaki zamanlayıcı, reddedilen bir çalışmanın önceliğini de güncelleyebilir.
// priority_queueSchedulerPriority.cpp
#include <concepts>
#include <coroutine>
#include <functional>
#include <iostream>
#include <queue>
#include <utility>
struct Task {
struct promise_type {
std::suspend_always initial_suspend() noexcept { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
Task get_return_object() {
return std::coroutine_handle<promise_type>::from_promise(*this);
}
void return_void() {}
void unhandled_exception() {}
};
Task(std::coroutine_handle<promise_type> handle): handle{handle}{}
auto get_handle() { return handle; }
std::coroutine_handle<promise_type> handle;
};
using job = std:
air<int, std::coroutine_handle<>>;
template <typename Updater = std::identity, // (1)
typename Comperator = std::ranges::less>
requires std::invocable<decltype(Updater()), int> && // (2)
std:
redicate<decltype(Comperator()), job, job>
class Scheduler {
std:
riority_queue<job, std::vector<job>, Comperator> _prioTasks;
public:
void emplace(int prio, std::coroutine_handle<> task) {
_prioTasks.push(std::make_pair(prio, task));
}
void schedule() {
Updater upd = {}; // (3)
while(!_prioTasks.empty()) {
auto [prio, task] = _prioTasks.top();
_prioTasks.pop();
task.resume();
if(!task.done()) {
_prioTasks.push(std::make_pair(upd(prio), task)); // (4)
}
else {
task.destroy();
}
}
}
};
Task createTask(const std::string& name) {
std::cout << name << " startn";
co_await std::suspend_always();
for (int i = 0; i <= 3; ++i ) {
std::cout << name << " execute " << i << "n"; // (5)
co_await std::suspend_always();
}
co_await std::suspend_always();
std::cout << name << " finishn";
}
int main() {
std::cout << 'n';
Scheduler scheduler1; // (6)
scheduler1.emplace(0, createTask("TaskA").get_handle());
scheduler1.emplace(1, createTask(" TaskB").get_handle());
scheduler1.emplace(2, createTask(" TaskC").get_handle());
scheduler1.schedule();
std::cout << 'n';
Scheduler<decltype([](int a) { return a - 1; })> scheduler2; //(7)
scheduler2.emplace(0, createTask("TaskA").get_handle());
scheduler2.emplace(1, createTask(" TaskB").get_handle());
scheduler2.emplace(2, createTask(" TaskC").get_handle());
scheduler2.schedule();
std::cout << 'n';
}
Programdaki programda yalnızca birkaç değişiklik var priority_queueSchedulerComparator.cpp Önceliklerin güncellenmesini desteklemek için gereklidir.
Her şeyden önce, zamanlayıcı ek bir model parametresi alır Updater (1), varsayılan değer std::identity kullanılmış. Updater çağrılmalı ve bir int farz etmek. Tabii ki öyle std::invocable Bir kavram (2). . Updater (3) 'de oluşturulur ve (4)' de uygulanır. Ayrıca, (5) 'de Careroutine, faaliyetlerin hangi kısmının gerçekleştirildiğini göstermektedir. scheduler1 (6) Görevini azami öncelikten başlayarak gerçekleştirir, ancak scheduler2 (7) Birinin restorasyonunun önceliğini azaltır. Calllone birimi olarak bir lambda kullanıyorum.
Program baskısı çeşitli planlama stratejilerini göstermektedir.
Sırada ne var?
Coroutins, eşzamansız bir kod yazmak için sezgisel bir yol sunar. Bir sonraki makalem, Ljubic Damir'in misafirleri için tek bir yapımcı sunduğu bir yazı olacak: koroya dayalı tek katlı iş akışı.
(RME)
C ++ Programlama Dili: Koro için zorlu bir öncelik zamanlayıcı
Bu, C ++ Coroutinen için zamanlayıcı ile ilgili mini serimin dördüncü makalesi. İlk iki makale Dian-Lun Lin'in konuklarının gönderileriydi:

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.
- Yazılım Geliştirme: Dian-Lun Li Choroutins'e Kompakt Giriş
- Coroutins: Etkinlikler İçin Bir Zamanlayıcı – Dian -Lun Li'nin 2. Bölümü
- C ++ Programlama Dili: Koro için öncelikli bir zamanlayıcı

Dian-Luns'un zamanlayıcısı konteyner adaptörüne dayanıyordu std::stack VE std::queue. . std::stack İlk çıkış stratejisinden sonra görevlerini dikin, ancak std::queue Sırtta birincisini kullanın. Sonunda benimkini destekliyor std:
Bu makalede en son programı iki şekilde geliştireceğim. Her şeyden önce, karşılaştırma işlevini kullanmak istiyorum. std:
Karşılaştırma işlevi
Öncelik kuyruğu her zaman en büyük unsuruna sahiptir. std:
// priority_queueSchedulerComparator.cpp
#include <concepts>
#include <coroutine>
#include <functional>
#include <iostream>
#include <queue>
#include <utility>
struct Task {
struct promise_type {
std::suspend_always initial_suspend() noexcept { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
Task get_return_object() {
return std::coroutine_handle<promise_type>::from_promise(*this);
}
void return_void() {}
void unhandled_exception() {}
};
Task(std::coroutine_handle<promise_type> handle): handle{handle}{}
auto get_handle() { return handle; }
std::coroutine_handle<promise_type> handle;
};
using job = std:
template <typename Comparator = std::ranges::less> // (2)
requires std:
class Scheduler {
std:
public:
void emplace(int prio, std::coroutine_handle<> task) {
_prioTasks.push(std::make_pair(prio, task));
}
void schedule() {
while(!_prioTasks.empty()) {
auto [prio, task] = _prioTasks.top();
_prioTasks.pop();
task.resume();
if(!task.done()) {
_prioTasks.push(std::make_pair(prio, task)); // (6)
}
else {
task.destroy();
}
}
}
};
Task createTask(const std::string& name) {
std::cout << name << " startn";
co_await std::suspend_always();
std::cout << name << " executen";
co_await std::suspend_always();
std::cout << name << " finishn";
}
int main() {
std::cout << 'n';
Scheduler scheduler1; // (4)
scheduler1.emplace(0, createTask("TaskA").get_handle());
scheduler1.emplace(1, createTask(" TaskB").get_handle());
scheduler1.schedule();
std::cout << 'n';
Scheduler<std::ranges::greater> scheduler2; // (5)
scheduler2.emplace(0, createTask("TaskA").get_handle());
scheduler2.emplace(1, createTask(" TaskB").get_handle());
scheduler2.schedule();
std::cout << 'n';
}
Zamanlayıcıyı ezenler dizinin önceki makalesini okumalıdır. Her şeyden önce, bir öncelik ve bir aktivite kombinasyonu diyorum (1). Zamanlayıcının bir model parametresine ihtiyacı var ComparatorVarsayılan değer std::ranges::less (2). Konsept de kontrol ediyor std::
scheduler1 (5) en üst düzey önceliğe göre çalışmaya başlar, scheduler2 (6) Öte yandan, en düşük önceliğe sahip çalışmalarla.

(6) 'da çalışmamı zamanlayıcı üzerine koydum. Görevlendirilen bir emrin önceliğini değiştirebilseydim iyi olmaz mıydı?
Önceliği Güncelle
Aşağıdaki zamanlayıcı, reddedilen bir çalışmanın önceliğini de güncelleyebilir.
// priority_queueSchedulerPriority.cpp
#include <concepts>
#include <coroutine>
#include <functional>
#include <iostream>
#include <queue>
#include <utility>
struct Task {
struct promise_type {
std::suspend_always initial_suspend() noexcept { return {}; }
std::suspend_always final_suspend() noexcept { return {}; }
Task get_return_object() {
return std::coroutine_handle<promise_type>::from_promise(*this);
}
void return_void() {}
void unhandled_exception() {}
};
Task(std::coroutine_handle<promise_type> handle): handle{handle}{}
auto get_handle() { return handle; }
std::coroutine_handle<promise_type> handle;
};
using job = std:
template <typename Updater = std::identity, // (1)
typename Comperator = std::ranges::less>
requires std::invocable<decltype(Updater()), int> && // (2)
std:
class Scheduler {
std:
public:
void emplace(int prio, std::coroutine_handle<> task) {
_prioTasks.push(std::make_pair(prio, task));
}
void schedule() {
Updater upd = {}; // (3)
while(!_prioTasks.empty()) {
auto [prio, task] = _prioTasks.top();
_prioTasks.pop();
task.resume();
if(!task.done()) {
_prioTasks.push(std::make_pair(upd(prio), task)); // (4)
}
else {
task.destroy();
}
}
}
};
Task createTask(const std::string& name) {
std::cout << name << " startn";
co_await std::suspend_always();
for (int i = 0; i <= 3; ++i ) {
std::cout << name << " execute " << i << "n"; // (5)
co_await std::suspend_always();
}
co_await std::suspend_always();
std::cout << name << " finishn";
}
int main() {
std::cout << 'n';
Scheduler scheduler1; // (6)
scheduler1.emplace(0, createTask("TaskA").get_handle());
scheduler1.emplace(1, createTask(" TaskB").get_handle());
scheduler1.emplace(2, createTask(" TaskC").get_handle());
scheduler1.schedule();
std::cout << 'n';
Scheduler<decltype([](int a) { return a - 1; })> scheduler2; //(7)
scheduler2.emplace(0, createTask("TaskA").get_handle());
scheduler2.emplace(1, createTask(" TaskB").get_handle());
scheduler2.emplace(2, createTask(" TaskC").get_handle());
scheduler2.schedule();
std::cout << 'n';
}
Programdaki programda yalnızca birkaç değişiklik var priority_queueSchedulerComparator.cpp Önceliklerin güncellenmesini desteklemek için gereklidir.
Her şeyden önce, zamanlayıcı ek bir model parametresi alır Updater (1), varsayılan değer std::identity kullanılmış. Updater çağrılmalı ve bir int farz etmek. Tabii ki öyle std::invocable Bir kavram (2). . Updater (3) 'de oluşturulur ve (4)' de uygulanır. Ayrıca, (5) 'de Careroutine, faaliyetlerin hangi kısmının gerçekleştirildiğini göstermektedir. scheduler1 (6) Görevini azami öncelikten başlayarak gerçekleştirir, ancak scheduler2 (7) Birinin restorasyonunun önceliğini azaltır. Calllone birimi olarak bir lambda kullanıyorum.
Program baskısı çeşitli planlama stratejilerini göstermektedir.

Sırada ne var?
Coroutins, eşzamansız bir kod yazmak için sezgisel bir yol sunar. Bir sonraki makalem, Ljubic Damir'in misafirleri için tek bir yapımcı sunduğu bir yazı olacak: koroya dayalı tek katlı iş akışı.
(RME)