C++ Programlama Dili: Eşyordamlar için öncelikli zamanlayıcı

Adanali

Active member
C++ Programlama Dili: Eşyordamlar için öncelikli zamanlayıcı


  1. C++ Programlama Dili: Eşyordamlar için öncelikli zamanlayıcı

Bu, C++ eşyordamları için zamanlayıcılar hakkındaki mini dizimin üçüncü makalesi. İlk iki makale Dian-Lun Lin’in konuk gönderileriydi:

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.













Dian-Lun’un zamanlayıcıları std::stack ve std::queue konteyner adaptörünü temel alıyordu. THE std::stack Görevlerini son giren ilk çıkar stratejisine göre yürütür std::queue Ancak ilk giren ilk çıkar ilkesine göre.

Aşağıdaki kod parçacığı kuyruk tabanlı zamanlayıcıyı gösterir:


class Scheduler {

std::queue<std::coroutine_handle<>> _tasks;&#13;
&#13;
public: &#13;
&#13;
void emplace(std::coroutine_handle<> task) {&#13;
_tasks.push(task);&#13;
}&#13;
&#13;
void schedule() {&#13;
while(!_tasks.empty()) {&#13;
auto task = _tasks.front();&#13;
_tasks.pop();&#13;
task.resume();&#13;
&#13;
if(!task.done()) { &#13;
_tasks.push(task);&#13;
}&#13;
else {&#13;
task.destroy();&#13;
}&#13;
}&#13;
}&#13;
&#13;
auto suspend() {&#13;
return std::suspend_always{};&#13;
}&#13;
};


Bu zamanlayıcıya öncelikler eklemek oldukça basittir.

Öncelik sıralarına dayalı bir zamanlayıcı


std::priority_queue yakında std::stack VE std::queue C++98’deki üçüncü konteyner bağdaştırıcısı.

THE std::priority_queue ve std::queue benzer. Temel fark, en büyük öğenin her zaman öncelik sırasının en üstünde yer almasıdır. std::priority_queue karşılaştırma operatörü varsayılan olarak kullanılır std::less. THE Nachschlagezeit birinde std::priority_queue sabittir ancak ekleme ve çıkarma logaritmiktir.

onu değiştireceğim std::queue önceki zamanlayıcıda -den -e std::priority_queue:


// priority_queueScheduler.cpp&#13;
&#13;
#include <coroutine>&#13;
#include <iostream>&#13;
#include <queue>&#13;
#include <utility>&#13;
&#13;
&#13;
struct Task {&#13;
&#13;
struct promise_type {&#13;
std::suspend_always initial_suspend() noexcept { return {}; }&#13;
std::suspend_always final_suspend() noexcept { return {}; }&#13;
&#13;
Task get_return_object() { &#13;
return std::coroutine_handle<promise_type>::from_promise(*this); &#13;
}&#13;
void return_void() {}&#13;
void unhandled_exception() {}&#13;
};&#13;
&#13;
Task(std::coroutine_handle<promise_type> handle): handle{handle}{}&#13;
&#13;
auto get_handle() { return handle; }&#13;
&#13;
std::coroutine_handle<promise_type> handle;&#13;
};&#13;
&#13;
class Scheduler {&#13;
// (1)&#13;
std::priority_queue<std::pair<int, std::coroutine_handle<>>> _prioTasks;&#13;
&#13;
public: &#13;
&#13;
void emplace(int prio, std::coroutine_handle<> task) { // (2)&#13;
_prioTasks.push(std::make_pair(prio, task));&#13;
}&#13;
&#13;
void schedule() {&#13;
while(!_prioTasks.empty()) { // (3)&#13;
auto [prio, task] = _prioTasks.top();&#13;
_prioTasks.pop();&#13;
task.resume();&#13;
&#13;
if(!task.done()) { &#13;
_prioTasks.push(std::make_pair(prio, task)); // (4)&#13;
}&#13;
else {&#13;
task.destroy();&#13;
}&#13;
}&#13;
}&#13;
&#13;
auto suspend() {&#13;
return std::suspend_always{};&#13;
}&#13;
};&#13;
&#13;
&#13;
Task TaskA(Scheduler& sch) {&#13;
std::cout << "Hello from TaskAn";&#13;
co_await sch.suspend();&#13;
std::cout << "Executing the TaskAn";&#13;
co_await sch.suspend();&#13;
std::cout << "TaskA is finishedn";&#13;
}&#13;
&#13;
Task TaskB(Scheduler& sch) {&#13;
std::cout << "Hello from TaskBn";&#13;
co_await sch.suspend();&#13;
std::cout << "Executing the TaskBn";&#13;
co_await sch.suspend();&#13;
std::cout << "TaskB is finishedn";&#13;
}&#13;
&#13;
&#13;
int main() {&#13;
&#13;
std::cout << 'n';&#13;
&#13;
Scheduler scheduler1;&#13;
&#13;
scheduler1.emplace(0, TaskA(scheduler1).get_handle()); // (5) &#13;
scheduler1.emplace(1, TaskB(scheduler1).get_handle());&#13;
&#13;
scheduler1.schedule();&#13;
&#13;
std::cout << 'n';&#13;
&#13;
Scheduler scheduler2;&#13;
&#13;
scheduler2.emplace(1, TaskA(scheduler2).get_handle()); // (6)&#13;
scheduler2.emplace(0, TaskB(scheduler2).get_handle());&#13;
&#13;
scheduler2.schedule();&#13;
&#13;
std::cout << 'n';&#13;
&#13;
}


İlk önce şunu kullanın: std::priority_queue bir çift (öncelik, tutamaç) (1). Artık bu çift sahnede olacak. _prioTask (2) yerleştirildi. Zamanlayıcı çalışırken, _prioTask boştur (3), aksi takdirde ilk görev çağrılır, kaldırılır ve devam ettirilir. Görev tamamlanmazsa dosyaya iade edilecektir _prioTasks ertelendi (4).

Birinin kullanımı std::priority_queue<std::pair<int, std::coroutine_handle<>>> en yüksek öncelikli görevlerin ilk önce yapılması gibi güzel bir yan etkiye sahiptir. Faaliyetlerin zamanlayıcıya eklenme sırası hiçbir fark yaratmaz (5 ve 6); önceliği 1 olan görev ilk önce çalıştırılır.








Bir sonraki yazımda öncelik yönetimini geliştirmeden önce öncelikle koroutini basitleştirmek istiyorum.

Basitleştirilmiş eşyordam


İşte önceki koroutinler TaskA VE TaskB:


Task TaskA(Scheduler& sch) {&#13;
std::cout << "Hello from TaskAn";&#13;
co_await sch.suspend();&#13;
std::cout << "Executing the TaskAn";&#13;
co_await sch.suspend();&#13;
std::cout << "TaskA is finishedn";&#13;
}&#13;
&#13;
Task TaskB(Scheduler& sch) {&#13;
std::cout << "Hello from TaskBn";&#13;
co_await sch.suspend();&#13;
std::cout << "Executing the TaskBn";&#13;
co_await sch.suspend();&#13;
std::cout << "TaskB is finishedn";&#13;
}&#13;



Yerine co_await zamanlayıcıda, doğrudan varsayılan bekleyebilirliği çağırarak değiştiriyorum std::suspend_always. Zamanlayıcının üye askıya alma işlevini nasıl kaldırabileceğimi burada bulabilirsiniz. İkincisi: eşyordam görevine göre adlandırılmıştır:


Task createTask(const std::string& name) {&#13;
std::cout << name << " startn";&#13;
co_await std::suspend_always();&#13;
std::cout << name << " executen";&#13;
co_await std::suspend_always();&#13;
std::cout << name << " finishn";&#13;
}&#13;



Son olarak, karşılık gelen çıktıyı içeren basitleştirilmiş program burada.


// priority_queueSchedulerSimplified.cpp&#13;
&#13;
#include <coroutine>&#13;
#include <iostream>&#13;
#include <queue>&#13;
#include <utility>&#13;
&#13;
&#13;
struct Task {&#13;
&#13;
struct promise_type {&#13;
std::suspend_always initial_suspend() noexcept { return {}; }&#13;
std::suspend_always final_suspend() noexcept { return {}; }&#13;
&#13;
Task get_return_object() { &#13;
return std::coroutine_handle<promise_type>::from_promise(*this); &#13;
}&#13;
void return_void() {}&#13;
void unhandled_exception() {}&#13;
};&#13;
&#13;
Task(std::coroutine_handle<promise_type> handle): handle{handle}{}&#13;
&#13;
auto get_handle() { return handle; }&#13;
&#13;
std::coroutine_handle<promise_type> handle;&#13;
};&#13;
&#13;
class Scheduler {&#13;
&#13;
std::priority_queue<std::pair<int, std::coroutine_handle<>>> _prioTasks;&#13;
&#13;
public: &#13;
&#13;
void emplace(int prio, std::coroutine_handle<> task) {&#13;
_prioTasks.push(std::make_pair(prio, task));&#13;
}&#13;
&#13;
void schedule() {&#13;
while(!_prioTasks.empty()) {&#13;
auto [prio, task] = _prioTasks.top();&#13;
_prioTasks.pop();&#13;
task.resume();&#13;
&#13;
if(!task.done()) { &#13;
_prioTasks.push(std::make_pair(prio, task));&#13;
}&#13;
else {&#13;
task.destroy();&#13;
}&#13;
}&#13;
}&#13;
&#13;
};&#13;
&#13;
&#13;
Task createTask(const std::string& name) {&#13;
std::cout << name << " startn";&#13;
co_await std::suspend_always();&#13;
std::cout << name << " executen";&#13;
co_await std::suspend_always();&#13;
std::cout << name << " finishn";&#13;
}&#13;
&#13;
&#13;
int main() {&#13;
&#13;
std::cout << 'n';&#13;
&#13;
Scheduler scheduler1;&#13;
&#13;
scheduler1.emplace(0, createTask("TaskA").get_handle());&#13;
scheduler1.emplace(1, createTask(" TaskB").get_handle());&#13;
&#13;
scheduler1.schedule();&#13;
&#13;
std::cout << 'n';&#13;
&#13;
Scheduler scheduler2;&#13;
&#13;
scheduler2.emplace(1, createTask("TaskA").get_handle());&#13;
scheduler2.emplace(0, createTask(" TaskB").get_handle());&#13;
&#13;
scheduler2.schedule();&#13;
&#13;
std::cout << 'n';&#13;
&#13;
}








Sıradaki ne?


Bir sonraki yazımda görev öncelik yönetimini daha da geliştireceğim.


(kendim)



Haberin Sonu
 
Üst