Lecture 7

SFR1811·2022년 1월 28일
0

3.10 Full Coroutines

full coroutine has cycles

The simpliest coroutine!

_Coroutine Fc{
  void main(){
    mem();               // [3]
    resume();            // [6,7]
    suspend();           // [8,9]
  }
 public:
  void mem(){resume();}  // [2]/[4,5]
};

int main(){
  Fc fc;
  fc.mem();              // [1]/[10]
}

resume() makes

  1. current coroutine inactive
  2. 'this' coroutine active

When Fc resumes in main > mem() or main < resume(), it inactivates Fc coroutine, and activates 'this' coroutine, which is itself.

suspend() makes

  1. current coroutine inactive
  2. 'last resumer' active

Above example under Fc > main suspend(), notice that the 'last resumer' is itself from right above the line.

So Fc coroutine inactivates itself and activates the 'last resumer,' which is also itself.

BUT!!!, this is very counter intuitive. So if a coroutine calls resume on itself, it does not overwrite 'last resumer'

But suppose that you don't have the above special rule, what happens when Fc.main terminates?
It goes to the starter, not the last resumer as intuition says.


3.10.1 PingPong example

_Coroutin PingPong{
  const char * name;
  const unsigned int N;
  PingPong * part;
  void main() { // ping's starter ::main, pong's starter ping
    for(unsigned int i = 0; i<N; i += 1{
      cout << name << endl;
      part->cycle();
    }
  }
 public:
  PingPong(const char * name, unsigned int N, PingPong & part)
    : name(name), N(N), part(&part) {}
  PingPong(const char * name, unsigned int N)
    : name(name), N(N) {}
  void partner(PingPong & part) {PingPong::part = &part;}
  void cycle() {resume();}
};

int main(){
  PingPong ping("ping", N), pong("pong",N,ping);
  ping.partner(pong);
  ping.cycle();
}

3.10.2 Producer-Consumer with Full-Coroutine

_Event Stop {};
_Coroutine Prod {
  Cons *
  c;
  int N, money, receipt;
  void main() {
    for ( int i = 0; i < N; i += 1 ) {
      int p1 = rand() % 100;
      int p2 = rand() % 100;
      cout << "prod " << . . .
      int status = c->delivery(p1, p2);
      cout << "prod rec $" << . . .
      receipt += 1;
    }
    _Resume Stop() _At resumer();
    suspend(); // restart cons
    cout << "prod stops" << endl;
  }
 public:
  int payment( int money ) {
    Prod::money = money;
    resume();
    return receipt;
  }
  void start( int N, Cons & c ) {
    Prod::N = N; Prod::c = &c;
    receipt = 0;
    resume();
  }
};

_Coroutine Cons {
  Prod & p;
  int p1, p2, status = 0;
  void main() {
    int money = 1, receipt;
    try {
      for ( ;; ) {
        cout << "cons " << p1 << . . .
        status += 1;
        receipt = p.payment( money );
        cout << "cons #" << . . .
        money += 1;
        _Enable; // trigger exception
      }
    } catch( Stop & ) {}
    cout << "cons stops" << endl;
  }
 public:
  Cons( Prod & p ) : p( p ) {}
  int delivery( int p1, int p2 ) {
    Cons::p1 = p1; Cons::p2 = p2;
    resume();
    return status;
  }
};

Instead of using flag variables to escape the coroutine cycle, it is using non-local exception "Stop"

profile
3B CS

0개의 댓글