Coroutins: Dian-Lun LI etkinlik etkinlikleri için bir zamanlayıcı
Bu blog yazısı, bir görev zamanlayıcısı için mini dizinin ikinci kısmıdır ve önceki “Yazılım Geliştirme: Dian-Lun Li'nin Kompakt Croutinen tanıtımı” adlı makalesine dayanmaktadır.
C ++-Coroutins için tek bir tel programı
Bu bölümde Choroutinen'i planlamak için tek bir iş parçacığı programı uyguluyorum. Arayüz ile başlayalım:
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() {
Scheduler sch;
sch.emplace(TaskA(sch).get_handle());
sch.emplace(TaskB(sch).get_handle());
std::cout << "Start scheduling...n";
sch.schedule();
İlave olarak TaskA ilave olarak TaskB Onlar koroutin. İçinde main-Bir zamanlayıcı oluşturun ve iki etkinliği (koro tutamaçları) zamanlayıcı içine yerleştirin. Bu yüzden arıyorum schedule İki görevi planlamak için. Etkinlik, aşağıdaki gibi tanımlanan bir koro nesnesidir:
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;
};
İşlevde olduğuma dikkat edilmelidir initial_suspend ve işlevde final_suspend std::suspend_always geri dönmek. Bu gereklidir çünkü Choroutines'in tüm yürütülmesini zamanlayıcıya teslim etmek istiyorum. Choroutins sadece ben schedule Çağrılar. Zamanlayıcı aşağıdaki gibi tanımlanır:
class Scheduler {
//std::queue<std::coroutine_handle<>> _tasks;
std::stack<std::coroutine_handle<>> _tasks;
public:
void emplace(std::coroutine_handle<> task) {
_tasks.push(task);
}
void schedule() {
while(!_tasks.empty()) {
//auto task = _tasks.front();
auto task = _tasks.top();
_tasks.pop();
task.resume();
if(!task.done()) {
_tasks.push(task);
}
else {
task.destroy();
}
}
}
auto suspend() {
return std::suspend_always{};
}
};
Bir yığın içindeki zamanlayıcı tasarruf etkinliğinde emplace-Bu işlevin, kullanıcıların yığının üzerindeki bir etkinliği basabilmesi için zamanlama. İçinde schedule-Meme Yığından bir etkinliği kaldırmaya devam ediyorum. Bir etkinlik aldığımda, etkinliğin gerçekleştirilip gerçekleştirilmediğini kontrol edin. Aksi takdirde, daha sonra planlamak için yığın üzerindeki etkinliği iterim. Aksi takdirde bitmiş görevi yok ediyorum. Program gerçekleştikten sonra aşağıdaki sonuçlar mevcuttur:
Zamanlayıcı, etkinlikleri kaydetmek için bir yığın (önce yükle) kullanır. Yığını bir sinyalle değiştirirsem (ilk olarak, ilk dışarıda), faaliyetlerin yürütülme sırası değişir:
Tamlık için, her iki program da burada tekrar özetlenmiştir:
// stackScheduler.cpp
#include <coroutine>
#include <iostream>
#include <stack>
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::stack<std::coroutine_handle<>> _tasks;
public:
void emplace(std::coroutine_handle<> task) {
_tasks.push(task);
}
void schedule() {
while(!_tasks.empty()) {
auto task = _tasks.top();
_tasks.pop();
task.resume();
if(!task.done()) {
_tasks.push(task);
}
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 sch;
sch.emplace(TaskA(sch).get_handle());
sch.emplace(TaskB(sch).get_handle());
std::cout << "Start scheduling...n";
sch.schedule();
std::cout << 'n';
}
// queueScheduler.cpp
#include <coroutine>
#include <iostream>
#include <queue>
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::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{};
}
};
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 sch;
sch.emplace(TaskA(sch).get_handle());
sch.emplace(TaskB(sch).get_handle());
std::cout << "Start scheduling...n";
sch.schedule();
std::cout << 'n';
}
Sırada ne var?
Dian-Lun'un bu makalesi onlara basit bir koro programı gösteriyor. Bir sonraki yazımda daha fazla deney için Dian-Luns zamanlayıcı kullanıyorum.
(harita)
Bu blog yazısı, bir görev zamanlayıcısı için mini dizinin ikinci kısmıdır ve önceki “Yazılım Geliştirme: Dian-Lun Li'nin Kompakt Croutinen tanıtımı” adlı makalesine dayanmaktadır.

C ++-Coroutins için tek bir tel programı
Bu bölümde Choroutinen'i planlamak için tek bir iş parçacığı programı uyguluyorum. Arayüz ile başlayalım:
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() {
Scheduler sch;
sch.emplace(TaskA(sch).get_handle());
sch.emplace(TaskB(sch).get_handle());
std::cout << "Start scheduling...n";
sch.schedule();
İlave olarak TaskA ilave olarak TaskB Onlar koroutin. İçinde main-Bir zamanlayıcı oluşturun ve iki etkinliği (koro tutamaçları) zamanlayıcı içine yerleştirin. Bu yüzden arıyorum schedule İki görevi planlamak için. Etkinlik, aşağıdaki gibi tanımlanan bir koro nesnesidir:
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;
};
İşlevde olduğuma dikkat edilmelidir initial_suspend ve işlevde final_suspend std::suspend_always geri dönmek. Bu gereklidir çünkü Choroutines'in tüm yürütülmesini zamanlayıcıya teslim etmek istiyorum. Choroutins sadece ben schedule Çağrılar. Zamanlayıcı aşağıdaki gibi tanımlanır:
class Scheduler {
//std::queue<std::coroutine_handle<>> _tasks;
std::stack<std::coroutine_handle<>> _tasks;
public:
void emplace(std::coroutine_handle<> task) {
_tasks.push(task);
}
void schedule() {
while(!_tasks.empty()) {
//auto task = _tasks.front();
auto task = _tasks.top();
_tasks.pop();
task.resume();
if(!task.done()) {
_tasks.push(task);
}
else {
task.destroy();
}
}
}
auto suspend() {
return std::suspend_always{};
}
};
Bir yığın içindeki zamanlayıcı tasarruf etkinliğinde emplace-Bu işlevin, kullanıcıların yığının üzerindeki bir etkinliği basabilmesi için zamanlama. İçinde schedule-Meme Yığından bir etkinliği kaldırmaya devam ediyorum. Bir etkinlik aldığımda, etkinliğin gerçekleştirilip gerçekleştirilmediğini kontrol edin. Aksi takdirde, daha sonra planlamak için yığın üzerindeki etkinliği iterim. Aksi takdirde bitmiş görevi yok ediyorum. Program gerçekleştikten sonra aşağıdaki sonuçlar mevcuttur:

Zamanlayıcı, etkinlikleri kaydetmek için bir yığın (önce yükle) kullanır. Yığını bir sinyalle değiştirirsem (ilk olarak, ilk dışarıda), faaliyetlerin yürütülme sırası değişir:

Tamlık için, her iki program da burada tekrar özetlenmiştir:
// stackScheduler.cpp
#include <coroutine>
#include <iostream>
#include <stack>
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::stack<std::coroutine_handle<>> _tasks;
public:
void emplace(std::coroutine_handle<> task) {
_tasks.push(task);
}
void schedule() {
while(!_tasks.empty()) {
auto task = _tasks.top();
_tasks.pop();
task.resume();
if(!task.done()) {
_tasks.push(task);
}
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 sch;
sch.emplace(TaskA(sch).get_handle());
sch.emplace(TaskB(sch).get_handle());
std::cout << "Start scheduling...n";
sch.schedule();
std::cout << 'n';
}
// queueScheduler.cpp
#include <coroutine>
#include <iostream>
#include <queue>
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::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{};
}
};
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 sch;
sch.emplace(TaskA(sch).get_handle());
sch.emplace(TaskB(sch).get_handle());
std::cout << "Start scheduling...n";
sch.schedule();
std::cout << 'n';
}
Sırada ne var?
Dian-Lun'un bu makalesi onlara basit bir koro programı gösteriyor. Bir sonraki yazımda daha fazla deney için Dian-Luns zamanlayıcı kullanıyorum.
(harita)