How do you implement Coroutines in C++

后端 未结 18 992
刺人心
刺人心 2020-12-02 04:17

I doubt it can be done portably, but are there any solutions out there? I think it could be done by creating an alternate stack and reseting SP,BP, and IP on function entry

18条回答
  •  清歌不尽
    2020-12-02 05:00

    Based on macros as well (Duff's device, fully portable, see http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html ) and inspired by the link posted by Mark, the following emulates co-processes collaborating using events as synchronization mechanism (slightly different model than the traditional co-routines/generator style)

    // Coprocess.h
    #pragma once
    #include 
    
    class Coprocess {
      public:
        Coprocess() : line_(0) {}
        void start() { line_ =  0; run(); }
        void end()   { line_ = -1; on_end(); }
        virtual void run() = 0;
        virtual void on_end() {}; 
      protected:
        int line_;
    };
    
    class Event {
      public:
        Event() : curr_(0) {}
    
        void wait(Coprocess* p) { waiters_[curr_].push_back(p); }
    
        void notify() {
            Waiters& old = waiters_[curr_];
            curr_ = 1 - curr_; // move to next ping/pong set of waiters
            waiters_[curr_].clear();
            for (Waiters::const_iterator I=old.begin(), E=old.end(); I != E; ++I)
                (*I)->run();
        }   
      private:
        typedef std::vector Waiters;
        int curr_;
        Waiters waiters_[2];
    };
    
    #define corun()   run() { switch(line_) { case 0:
    #define cowait(e) line_=__LINE__; e.wait(this); return; case __LINE__:
    #define coend     default:; }} void on_end()
    

    An example of use:

    // main.cpp
    #include "Coprocess.h"
    #include 
    
    Event e;
    long sum=0;
    
    struct Fa : public Coprocess {
        int n, i;
        Fa(int x=1) : n(x) {}
        void corun() {
            std::cout << i << " starts\n";
            for (i=0; ; i+=n) {
                cowait(e);
                sum += i;
            }
        } coend {
            std::cout << n << " ended " << i << std::endl;
        }   
    };
    
    int main() {
        // create 2 collaborating processes
        Fa f1(5);
        Fa f2(10);
    
        // start them
        f1.start();
        f2.start();
        for (int k=0; k<=100; k++) { 
            e.notify();
        }   
        // optional (only if need to restart them)
        f1.end();
        f2.end();
    
        f1.start(); // coprocesses can be restarted
        std::cout << "sum " << sum << "\n";
        return 0;
    }
    

提交回复
热议问题