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
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;
}