C++11實現的協程庫,支持Win,Linux,Mac

C++11實現的協程庫,支持Win,Linux,Mac。

Fork Form https://github.com/mfichman/coro/commit/2d597a7ebe08bc28d91b98c942be17eb224b8853

C++ 協程的消息還是挺少的,補充一份。

協同程序(coroutine)簡稱協程

協同程序

參考Lua中協同程序的介紹

http://www.runoob.com/lua/lua-coroutine.html


Coroutine 協程類

協程類,用於封裝函數。一個協程只能包含一個函數,在執行期間的任何時刻可暫停和恢復。每個協程分配CORO_STACK_SIZE(1M)的內存大小。

class Coroutine : public std::enable_shared_from_this<Coroutine> {

Coroutine(F func);  // 構造函數,參數是一個函數,作爲綁定函數

void start() throw();  // 執行綁定函數
內部 func_();  // 執行綁定的函數
	 event_->notifyAll();

void exit(); //當協程完成執行時,此函數運行。
內部event_->notifyAll();
	main()->swap();

void swap(); // 將運行權給其它協程,當前正在執行的協程會掛起。

void yield();  // 掛起coroutine,將coroutine設置爲掛起狀態。RUNNING狀態切換爲RUNNABLE狀態,下次循環會繼續運行


void block(); // 阻止當前協同程序,直到發生某些I/O事件。 協程會在明確安排之前不得重新安排。RUNNING狀態切換爲BLOCKED狀態
內部hub()->blocked_++;

void unblock(); // 解除阻止
內部hub()->blocked_--;

void wait(); // 阻止當前協同程序,直到發生某些事件。 協程不會被重新安排,直到明確安排。BLOCKED狀態切換爲RUNNABLE狀態
內部hub()->waiting_++;

void notify(); // 在事件發生時取消阻止協同程序。
內部hub()->waiting_--;

// 部分成員變量
Ptr<Event> event_;  // 信號
}
Coroutine 狀態切換

這個狀態的過程比較的重要!

1、NEW --> RUNNING --> EXITED

2、RUNNING --> BLOCKED --> RUNNABLE --> RUNNING --> EXITED

3、WAITING --> RUNNABLE --> RUNNING --> EXITED

Coroutine::Coroutine(); // 初始化狀態爲RUNNING狀態

Coroutine::~Coroutine(): // 切換爲DELETED狀態

void Coroutine::wait(); // RUNNING切換爲WAITING狀態

void Coroutine::notify(); // WAITING切換爲RUNNABLE狀態

void Coroutine::swap(); // 當前RUNNABLE切換爲RUNNING;NEW切換爲RUNNING;BLOCKED切換爲RUNNING。最重要的函數,控制協程的中斷,切換。

void Coroutine::exit(); // RUNNING切換爲EXITED狀態

void Coroutine::yield(); // RUNNING切換爲RUNNABLE狀態

void Coroutine::block(); // RUNNING切換爲BLOCKED狀態

void Coroutine::unblock(); // BLOCKED切換爲RUNNABLE狀態


Coroutine 內存分配

每個協程分配CORO_STACK_SIZE(1M)的內存大小,保存到成員變量
Stack stack_;,所分配的內存會在Coroutine析構函數執行後釋放。

if defined(_WIN32)
struct StackFrame {
    void* fs8;		// 棧頂
    void* fs4;		// 棧低
    void* fs0;		// Root-level SEH handler
    void* rdi;
    void* rsi;
    void* rdx;
    void* rcx;
    void* rbx;
    void* rax;
    void* rbp;
    void* returnAddr; // coroStart() stack frame here
};

stackPointer_ // 保存初始化的信息地址,未被調用。

Coroutine析構的時候釋放內存。

Event 協程同步事件

協程的調用過程是單線程的,Event的控制是通過改變協程的狀態來控制的。

void notifyAll(); // 通知所有協程運行,添加到std::vector<EventRecord>容器中
void wait();  // 等待協程信號。實際是將協程的RUNNING切換爲WAITING狀態並掛起,調用其他的協程。
Hub 管理協程容器

Hub類管理所有coroutines,events和I/O。
等待的事件(通道,I/O等)發出完成信號,在執行調用。

被定義爲一個靜態變量,通過coro::run()調用。

void quiesce(); // 遍歷runnable_協程容器,更新協程的狀態(void Coroutine::swap()),將RUNNABLE狀態的協程保存到runnable_容器。

void poll(); // 輪詢I/O事件。

void Hub::run(); // 循環運行,每次取一個協程
常用API
// 添加函數到協程容器
coro::start(baz);

// 掛起,RUNNING狀態切換爲RUNNABLE狀態
coro::yield();

// 函數中調用,用於定時中斷,中斷時間到,繼續執行
coro::sleep(coro::Time::millisec(1000));

// 執行協程容器
coro::run(); 
Demo1 - Basic 基礎例子
#include "coro/Common.hpp"
#include "coro/Coroutine.hpp"
#include "coro/Hub.hpp"

void bar() {
    for (auto i = 0; i < 2; ++i) {
        coro::sleep(coro::Time::millisec(1000));
        std::cout << "barrrrrr" << std::endl;
    }
}

void baz() {
    for (auto i = 0; i < 20; ++i) {
        coro::sleep(coro::Time::millisec(100));
        std::cout << "baz" << std::endl;
    }
}

int main() {
    auto cbaz = coro::start(baz);
    auto cbar = coro::start(bar);
    coro::run();
    return 0;
}
Demo2 - Event 帶信號的例子
#include <coro/Common.hpp>
#include <coro/coro.hpp>

int main() {
    auto event = coro::Event();
    auto trigger = false;

    auto notifier = coro::start([&]() {
        printf("notified\n");
        trigger = true;
        event.notifyAll();	// 切換所有WAITING狀態的協程爲RUNNABLE狀態
    });

    auto waiter = coro::start([&]() {
        printf("waiting\n");
        event.wait([&]() { return trigger; });  // 等待信號
        printf("done\n");
    });

    coro::run();

    return 0;
}
Demo3 - Join 嵌套例子
#include <coro/Common.hpp>
#include <coro/coro.hpp>

int main() {
    auto counter = 0;
    auto one = coro::start([&]{
        coro::yield();  // 掛起,RUNNING切換爲RUNNABLE狀態。恢復的時候繼續運行下去
        assert(counter==0);
        counter++;
		std::cout << "one func" << counter << std::endl;
    });
    auto two = coro::start([&]{
        one->join();  // two狀態有RUNNING改爲WAITING;one狀態由RUNNABLE改爲RUNNING。
        assert(counter==1);
		std::cout <<"two func" << counter << std::endl;
    });

    coro::run();  // 
    return 0;
}
Demo4 - Selector 信號和協程綁定

使用這個類,開發者可以決定是否執行協程函數。
Selector局部變量析構函數中會將協程的狀態由RUNNING切換爲WAITING。Selector中可以保持多個協程對象。


#include <coro/Common.hpp>
#include <coro/coro.hpp>

using namespace coro;

Ptr<Event> e1(new Event);
Ptr<Event> e2(new Event);
Ptr<Event> e3(new Event);

void publisher() {
    e1->notifyAll();	// 通知執行
    e2->notifyAll();	// 通知執行
}

void consumer() {
    int count = 2;
    while (count > 0) {
        coro::Selector()  // 綁定信號和協程對象
            .on(e1, [&]() { count--; std::cout << "e1" << std::endl; })
            .on(e2, [&]() { count--; std::cout << "e2" << std::endl; })
            .on(e3, [&]() { std::cout << "e3" << std::endl; });
    }
}

int main() {
    auto b = coro::start(consumer);
    auto a = coro::start(publisher);

    coro::run();

    return 0;
}
GitHub

https://github.com/wanttobeno/libcoro.git

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章