C ++ Dil Programları: Choroutine için öncelikli bir zamanlayıcı
Bu, C ++ Coroutinen için zamanlayıcı ile ilgili mini serimin üçü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 Scheduer, Std :: Stack ve Std :: Coda konteyneri temelini çekti. . std::stack görevlerini ilk çıkış stratejisine göre yönlendirin, std::queue Öte yandan, ilk çıkışa göre.
Aşağıdaki kod parçası, kuyruk tabanlı zamanlayıcıdır:
class Scheduler {
std::queue<std::coroutine_handle<>> _tasks;
public:
void emplace(std::coroutine_handle<> task) {
_tasks.push(task);
}
void schedule() {
while(!_tasks.empty()) {
auto task = _tasks.front();
_tasks.pop();
task.resume();
if(!task.done()) {
_tasks.push(task);
}
else {
task.destroy();
}
}
}
auto suspend() {
return std::suspend_always{};
}
};
Bu öncelik programını genişletmek oldukça basittir.
Öncelik tabanlı bir zamanlayıcı
std:
riority_queue Yanında std::stack VE std::queue C ++ 98'deki üçüncü konteyner adaptörü.
. std:
riority_queue öyle std::queue benzer. Temel fark, en büyük unsurlarının her zaman öncelik kuyruğunun üstünde olmasıdır. std:
riority_queue Varsayılan olarak karşılaştırma operatörünü kullanmak std::less. . Nachschlagezeit birinde std:
riority_queue Sabittir, ancak eklemek ve ortadan kaldırmak logaritmiktir.
Onları değiştiriyorum std::queue Bir dosya aracılığıyla önceki programda std:
riority_queue:
// priority_queueScheduler.cpp
#include <coroutine>
#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;
};
class Scheduler {
// (1)
std:
riority_queue<std:
air<int, std::coroutine_handle<>>> _prioTasks;
public:
void emplace(int prio, std::coroutine_handle<> task) { // (2)
_prioTasks.push(std::make_pair(prio, task));
}
void schedule() {
while(!_prioTasks.empty()) { // (3)
auto [prio, task] = _prioTasks.top();
_prioTasks.pop();
task.resume();
if(!task.done()) {
_prioTasks.push(std::make_pair(prio, task)); // (4)
}
else {
task.destroy();
}
}
}
auto suspend() {
return std::suspend_always{};
}
};
Task TaskA(Scheduler& sch) {
std::cout << "Hello from TaskAn";
co_await sch.suspend();
std::cout << "Executing the TaskAn";
co_await sch.suspend();
std::cout << "TaskA is finishedn";
}
Task TaskB(Scheduler& sch) {
std::cout << "Hello from TaskBn";
co_await sch.suspend();
std::cout << "Executing the TaskBn";
co_await sch.suspend();
std::cout << "TaskB is finishedn";
}
int main() {
std::cout << 'n';
Scheduler scheduler1;
scheduler1.emplace(0, TaskA(scheduler1).get_handle()); // (5)
scheduler1.emplace(1, TaskB(scheduler1).get_handle());
scheduler1.schedule();
std::cout << 'n';
Scheduler scheduler2;
scheduler2.emplace(1, TaskA(scheduler2).get_handle()); // (6)
scheduler2.emplace(0, TaskB(scheduler2).get_handle());
scheduler2.schedule();
std::cout << 'n';
}
İlk olarak std:
riority_queue Bir çift (öncelik, sap) (1). Şimdi bu çift açık olacak _prioTask Yayınlanan (2). Zamanlayıcı gerçekleştirdiğinde, _prioTask Boştur (3), aksi takdirde ilk görev çağrılır, kaldırılır ve alınır. Etkinlik bitmediğinde, _prioTasks taşındı (4).
Bir kullanımı std:
riority_queue<std:
air<int, std::coroutine_handle<>>> Görevlerin ilk kez daha yüksek bir öncelikle gerçekleştirildiği hoş yan etkiye sahiptir. Faaliyetlerin zamanlayıcı (5 ve 6) üzerinde konumlandırıldığı sırada hiçbir fark yaratmaz; Öncelikli etkinlik 1 önce çalışır.
Bir sonraki makalemdeki öncelik tedavinizi geliştirmeden önce bakıcıyı basitleştirmek istiyorum.
Basitleştirilmiş Koro
İşte önceki choutines TaskA VE TaskB:
Task TaskA(Scheduler& sch) {
std::cout << "Hello from TaskAn";
co_await sch.suspend();
std::cout << "Executing the TaskAn";
co_await sch.suspend();
std::cout << "TaskA is finishedn";
}
Task TaskB(Scheduler& sch) {
std::cout << "Hello from TaskBn";
co_await sch.suspend();
std::cout << "Executing the TaskBn";
co_await sch.suspend();
std::cout << "TaskB is finishedn";
}
Yerine co_await Zamanlayıcı arayın, önceden tanımlanmış beklentiyi doğrudan arayarak değiştiriyorum std::suspend_always. Böylece zamanlayıcı süspansiyonunu kaldırabilirim. İkincisi, koro faaliyetlerinizin adını alır:
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";
}
Son olarak, ilgili baskı ile basitleştirilmiş program.
// priority_queueSchedulerSimplified.cpp
#include <coroutine>
#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;
};
class Scheduler {
std:
riority_queue<std:
air<int, std::coroutine_handle<>>> _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));
}
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;
scheduler1.emplace(0, createTask("TaskA").get_handle());
scheduler1.emplace(1, createTask(" TaskB").get_handle());
scheduler1.schedule();
std::cout << 'n';
Scheduler scheduler2;
scheduler2.emplace(1, createTask("TaskA").get_handle());
scheduler2.emplace(0, createTask(" TaskB").get_handle());
scheduler2.schedule();
std::cout << 'n';
}
Sırada ne var?
Bir sonraki makalemde, görevlerin öncelikli tedavisini daha da geliştireceğim.
(RME)
C ++ Dil Programları: Choroutine için öncelikli bir zamanlayıcı
Bu, C ++ Coroutinen için zamanlayıcı ile ilgili mini serimin üçü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 Scheduer, Std :: Stack ve Std :: Coda konteyneri temelini çekti. . std::stack görevlerini ilk çıkış stratejisine göre yönlendirin, std::queue Öte yandan, ilk çıkışa göre.
Aşağıdaki kod parçası, kuyruk tabanlı zamanlayıcıdır:
class Scheduler {
std::queue<std::coroutine_handle<>> _tasks;
public:
void emplace(std::coroutine_handle<> task) {
_tasks.push(task);
}
void schedule() {
while(!_tasks.empty()) {
auto task = _tasks.front();
_tasks.pop();
task.resume();
if(!task.done()) {
_tasks.push(task);
}
else {
task.destroy();
}
}
}
auto suspend() {
return std::suspend_always{};
}
};
Bu öncelik programını genişletmek oldukça basittir.
Öncelik tabanlı bir zamanlayıcı
std:
. std:
Onları değiştiriyorum std::queue Bir dosya aracılığıyla önceki programda std:
// priority_queueScheduler.cpp
#include <coroutine>
#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;
};
class Scheduler {
// (1)
std:
public:
void emplace(int prio, std::coroutine_handle<> task) { // (2)
_prioTasks.push(std::make_pair(prio, task));
}
void schedule() {
while(!_prioTasks.empty()) { // (3)
auto [prio, task] = _prioTasks.top();
_prioTasks.pop();
task.resume();
if(!task.done()) {
_prioTasks.push(std::make_pair(prio, task)); // (4)
}
else {
task.destroy();
}
}
}
auto suspend() {
return std::suspend_always{};
}
};
Task TaskA(Scheduler& sch) {
std::cout << "Hello from TaskAn";
co_await sch.suspend();
std::cout << "Executing the TaskAn";
co_await sch.suspend();
std::cout << "TaskA is finishedn";
}
Task TaskB(Scheduler& sch) {
std::cout << "Hello from TaskBn";
co_await sch.suspend();
std::cout << "Executing the TaskBn";
co_await sch.suspend();
std::cout << "TaskB is finishedn";
}
int main() {
std::cout << 'n';
Scheduler scheduler1;
scheduler1.emplace(0, TaskA(scheduler1).get_handle()); // (5)
scheduler1.emplace(1, TaskB(scheduler1).get_handle());
scheduler1.schedule();
std::cout << 'n';
Scheduler scheduler2;
scheduler2.emplace(1, TaskA(scheduler2).get_handle()); // (6)
scheduler2.emplace(0, TaskB(scheduler2).get_handle());
scheduler2.schedule();
std::cout << 'n';
}
İlk olarak std:
Bir kullanımı std:

Bir sonraki makalemdeki öncelik tedavinizi geliştirmeden önce bakıcıyı basitleştirmek istiyorum.
Basitleştirilmiş Koro
İşte önceki choutines TaskA VE TaskB:
Task TaskA(Scheduler& sch) {
std::cout << "Hello from TaskAn";
co_await sch.suspend();
std::cout << "Executing the TaskAn";
co_await sch.suspend();
std::cout << "TaskA is finishedn";
}
Task TaskB(Scheduler& sch) {
std::cout << "Hello from TaskBn";
co_await sch.suspend();
std::cout << "Executing the TaskBn";
co_await sch.suspend();
std::cout << "TaskB is finishedn";
}
Yerine co_await Zamanlayıcı arayın, önceden tanımlanmış beklentiyi doğrudan arayarak değiştiriyorum std::suspend_always. Böylece zamanlayıcı süspansiyonunu kaldırabilirim. İkincisi, koro faaliyetlerinizin adını alır:
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";
}
Son olarak, ilgili baskı ile basitleştirilmiş program.
// priority_queueSchedulerSimplified.cpp
#include <coroutine>
#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;
};
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));
}
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;
scheduler1.emplace(0, createTask("TaskA").get_handle());
scheduler1.emplace(1, createTask(" TaskB").get_handle());
scheduler1.schedule();
std::cout << 'n';
Scheduler scheduler2;
scheduler2.emplace(1, createTask("TaskA").get_handle());
scheduler2.emplace(0, createTask(" TaskB").get_handle());
scheduler2.schedule();
std::cout << 'n';
}

Sırada ne var?
Bir sonraki makalemde, görevlerin öncelikli tedavisini daha da geliştireceğim.
(RME)