基于windows fiber的协程(coroutine)实现
一个非常简单,但是实用的协程实现,使用Windows的*Fiber函数族(linux可以稍微改一下用*context函数族)。
fco.h
#ifndef _MSC_VER
#error "this fast coroutine library only supports MSVC building chain"
#endif
#include <Windows.h>
#include <cstdint>
#include <map>
namespace fco {
static constexpr int ERR_NOT_EXIST_CO = -1;
enum Status {
READY, // Set up to READY when fco::newco() called
AWAIT, // Set up to AWAIT when fco::yield() called
};
struct Scheduler;
struct Coroutine;
struct Coroutine {
void (*task)(Scheduler*, void*);
void* userData;
char status;
LPVOID winFiber;
};
struct Scheduler {
std::map<int, Coroutine*> coroutines;
int currentIdx;
LPVOID main;
};
void __stdcall __entry(LPVOID lpParameter);
Scheduler* initialize();
void destroy(Scheduler* s);
int newco(Scheduler* scheduler, void (*task)(Scheduler*, void*),
void* userData);
void resume(Scheduler* s, int coid);
void yield(Scheduler* scheduler);
int current(Scheduler* scheduler);
} // namespace fco
fco.cpp
#include "fco.h"
// Initialize fco library, return a global scheduler
fco::Scheduler* fco::initialize() {
Scheduler* sched = new Scheduler;
sched->currentIdx = ERR_NOT_EXIST_CO;
sched->main = ConvertThreadToFiber(NULL);
return sched;
}
// Release all resources
void fco::destroy(Scheduler* s) {
for (auto& c : s->coroutines) {
DeleteFiber(c.second->winFiber);
}
delete s;
}
// This is should NEVER BE called on user land
void __stdcall fco::__entry(LPVOID lpParameter) {
// Execute the task of current coroutine
Scheduler* s = (Scheduler*)lpParameter;
Coroutine* currentCo = s->coroutines[s->currentIdx];
(currentCo->task)(s, currentCo->userData);
// Clean up executed task
s->coroutines.erase(s->coroutines.find(s->currentIdx));
s->currentIdx = ERR_NOT_EXIST_CO;
currentCo->status = Status::READY;
DeleteFiber(currentCo->winFiber);
delete currentCo;
// Switch to entry function
SwitchToFiber(s->main);
}
// Create new coroutine and return an unique identity
int fco::newco(Scheduler* scheduler, void (*task)(fco::Scheduler*, void*),
void* userData) {
Coroutine* co = new Coroutine;
co->task = task;
co->userData = userData;
co->winFiber = CreateFiber(0, __entry, scheduler);
if (co->winFiber == NULL) {
return ERR_NOT_EXIST_CO;
}
co->status = Status::READY;
int newCoId =
scheduler->coroutines.size() != 0
? scheduler->coroutines.end().operator--().operator*().first + 1
: 0;
scheduler->coroutines.insert(std::make_pair(newCoId, co));
return newCoId;
}
// Resume suspended coroutine by given coid
void fco::resume(fco::Scheduler* scheduler, int coid) {
if (coid < 0) {
return;
}
Coroutine* co = scheduler->coroutines[coid];
if (co->status == Status::READY || co->status == Status::AWAIT) {
scheduler->currentIdx = coid;
scheduler->coroutines[scheduler->currentIdx]->status = Status::AWAIT;
co->status = Status::READY;
SwitchToFiber(co->winFiber);
}
}
// Yield CPU time to main coroutine
void fco::yield(fco::Scheduler* scheduler) {
Coroutine* co = scheduler->coroutines[scheduler->currentIdx];
co->status = Status::AWAIT;
scheduler->currentIdx = ERR_NOT_EXIST_CO;
SwitchToFiber(scheduler->main);
}
// Get current running coroutine identity
int fco::current(Scheduler* scheduler) { return scheduler->currentIdx; }
example
- hello world
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <vector>
#include "fco.h"
void bar(fco::Scheduler* s, void* param) {
for (int i = 0; i < 5; i++) {
std::cout << "world\n";
fco::yield(s);
}
}
int main() {
fco::Scheduler* s = fco::initialize();
int barFunc = fco::newco(s, bar, nullptr);
for (int i = 0; i < 5; i++) {
std::cout << "hello\n";
fco::resume(s, barFunc);
}
fco::destroy(s);
return 0;
}
- 生产者消费者模型
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <vector>
#include "fco.h"
std::vector<int> vec;
void producer(fco::Scheduler* s, void* param) {
while (vec.size() < 10) {
int resource = rand();
std::cout << "Producing " << resource << "\n";
vec.push_back(resource);
}
fco::resume(s, (int)param);
fco::yield(s);
}
void consumer(fco::Scheduler* s, void* param) {
int producerCo = fco::newco(s, producer, (void*)fco::current(s));
while (true) {
while (!vec.empty()) {
int resource = vec.back();
vec.pop_back();
std::cout << "Consuming " << resource << "\n";
}
fco::resume(s, producerCo);
}
}
void factory() {
fco::Scheduler* s = fco::initialize();
int consumerCo = fco::newco(s, consumer, nullptr);
fco::resume(s, consumerCo);
fco::destroy(s);
}
int main() {
srand((int)time(0));
factory();
system("pause");
return 0;
}
基于windows fiber的协程(coroutine)实现的更多相关文章
- 协程coroutine
协程(coroutine)顾名思义就是“协作的例程”(co-operative routines).跟具有操作系统概念的线程不一样,协程是在用户空间利用程序语言的语法语义就能实现逻辑上类似多任务的编程 ...
- qemu核心机制分析-协程coroutine
关于协程coroutine前面的文章已经介绍过了,本文总结对qemu中coroutine机制的分析,qemu 协程coroutine基于:setcontext函数族以及函数间跳转函数siglongjm ...
- Python并发编程协程(Coroutine)之Gevent
Gevent官网文档地址:http://www.gevent.org/contents.html 基本概念 我们通常所说的协程Coroutine其实是corporate routine的缩写,直接翻译 ...
- 并发编程协程(Coroutine)之Gevent
并发编程协程之Gevent Gevent官网文档地址:http://www.gevent.org/contents.html 基本概念 我们通常所说的协程Coroutine其实是corporate r ...
- Unity协程(Coroutine)管理类——TaskManager工具分享
博客分类: Unity3D插件学习,工具分享 源码分析 Unity协程(Coroutine)管理类——TaskManager工具分享 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处 ...
- (zt)Lua的多任务机制——协程(coroutine)
原帖:http://blog.csdn.net/soloist/article/details/329381 并发是现实世界的本质特征,而聪明的计算机科学家用来模拟并发的技术手段便是多任务机制.大致上 ...
- Lua的多任务机制——协程(coroutine)
并发是现实世界的本质特征,而聪明的计算机科学家用来模拟并发的技术手段便是多任务机制.大致上有这么两种多任务技术,一种是抢占式多任务(preemptive multitasking),它让操作系统来决定 ...
- Unity协程Coroutine使用总结和一些坑
原文摘自 Unity协程Coroutine使用总结和一些坑 MonoBehavior关于协程提供了下面几个接口: 可以使用函数或者函数名字符串来启动一个协程,同时可以用函数,函数名字符串,和Corou ...
- 【Unity】协程Coroutine及Yield常见用法
最近学习协程Coroutine,参考了别人的文章和视频教程,感觉协程用法还是相当灵活巧妙的,在此简单总结,方便自己以后回顾.Yield关键字的语意可以理解为“暂停”. 首先是yield return的 ...
随机推荐
- Library not found for -lAPOpenSdk
多人开发合作的时候 总是会遇见各种各样的问题 今天就来讲一个关于友盟的问题 在我的小伙伴 用cocoapods 中添加了这样一句话 pod ‘UMengSocialCOM’, 并且pod updat ...
- eval 是执行一段完整的js字符串代码,并将结果返回
var strArray="[{"message1":{ "id": "-1","content": &quo ...
- php static 变量声明
<?phpfunction test($key){ static $array = array(); /* 静态变量是只存在于函数作用域中的变量,注释:执行后这种变量不会丢失(下次调用这个函数 ...
- Halcon中一些突然想不起来但确实有用的算子
1.Develop dev_display 在现有图形窗口中显示图像目标. dev_set_color 设置一个或更多输出颜色,通常用于设置region或者xld的颜色. dev_set_dra ...
- Qt自定义插件编程小结
qt自定义组件开发步骤演示.以下所有步骤的前提是自己先编译Qtcreator源码,最好生成release版的QtCreator,否则自定义的插件嵌入QtCreator会失败!!!(这个网上教程很多) ...
- revert
git revert是用一次新的commit来回滚之前的commit
- Texstudio
Texstudio快捷键:Ctrl+T,选中之后按这个可以快速注释
- xStream完美转换XML、JSON(转)
xStream框架 xStream可以轻易的将Java对象和xml文档相互转换,而且可以修改某个特定的属性和节点名称,而且也支持json的转换: 前面有介绍过json-lib这个框架,在线博文:htt ...
- PCA 学习笔记
先简单记下,等有时间再整理 PCA 主要思想,把 协方差矩阵 对角化,协方差矩阵是实对称的.里面涉及到矩阵论的一点基础知识: 基变换: Base2 = P · Base1 相应的 坐标变换 P · c ...
- javascript总结39:DOM 中常用的表单元素的属性
1 常用操作元素: value 用于大部分表单元素的内容获取(option除外) type 可以获取input标签的类型(输入框或复选框等) disabled 禁用属性 checked 复选框选中属性 ...