我怀疑它可以便携地完成,但有什么解决方案吗?我认为可以通过创建一个备用堆栈并在函数入口处重置 SP、BP 和 IP,并让产量保存 IP 并恢复 SP+BP 来完成。析构函数和异常安全似乎很棘手,但可以解决。
已经完成了吗?这是不可能的吗?
原文由 Mike Elkins 发布,翻译遵循 CC BY-SA 4.0 许可协议
我怀疑它可以便携地完成,但有什么解决方案吗?我认为可以通过创建一个备用堆栈并在函数入口处重置 SP、BP 和 IP,并让产量保存 IP 并恢复 SP+BP 来完成。析构函数和异常安全似乎很棘手,但可以解决。
已经完成了吗?这是不可能的吗?
原文由 Mike Elkins 发布,翻译遵循 CC BY-SA 4.0 许可协议
也基于宏(Duff 的设备,完全可移植,参见 http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html )并受 Mark 发布的链接的启发,以下模拟协同进程协作使用事件作为同步机制(与传统的协程/生成器样式略有不同的模型)
// Coprocess.h
#pragma once
#include <vector>
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<Coprocess*> 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()
使用示例:
// main.cpp
#include "Coprocess.h"
#include <iostream>
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;
}
原文由 acppcoder 发布,翻译遵循 CC BY-SA 4.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.4k 阅读
1 回答3.3k 阅读
是的,它 可以毫无问题地完成。您只需要一点汇编代码就可以将调用堆栈移动到堆上新分配的堆栈。
我会 看看 boost::coroutine library 。
您应该注意的一件事是堆栈溢出。在大多数操作系统上,堆栈溢出将导致段错误,因为未映射虚拟内存页面。但是,如果您在堆上分配堆栈,您将得不到任何保证。要时刻铭记在心。