一个非常简单,但是实用的协程实现,使用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)实现的更多相关文章

  1. 协程coroutine

    协程(coroutine)顾名思义就是“协作的例程”(co-operative routines).跟具有操作系统概念的线程不一样,协程是在用户空间利用程序语言的语法语义就能实现逻辑上类似多任务的编程 ...

  2. qemu核心机制分析-协程coroutine

    关于协程coroutine前面的文章已经介绍过了,本文总结对qemu中coroutine机制的分析,qemu 协程coroutine基于:setcontext函数族以及函数间跳转函数siglongjm ...

  3. Python并发编程协程(Coroutine)之Gevent

    Gevent官网文档地址:http://www.gevent.org/contents.html 基本概念 我们通常所说的协程Coroutine其实是corporate routine的缩写,直接翻译 ...

  4. 并发编程协程(Coroutine)之Gevent

    并发编程协程之Gevent Gevent官网文档地址:http://www.gevent.org/contents.html 基本概念 我们通常所说的协程Coroutine其实是corporate r ...

  5. Unity协程(Coroutine)管理类——TaskManager工具分享

    博客分类: Unity3D插件学习,工具分享 源码分析   Unity协程(Coroutine)管理类——TaskManager工具分享 By D.S.Qiu 尊重他人的劳动,支持原创,转载请注明出处 ...

  6. (zt)Lua的多任务机制——协程(coroutine)

    原帖:http://blog.csdn.net/soloist/article/details/329381 并发是现实世界的本质特征,而聪明的计算机科学家用来模拟并发的技术手段便是多任务机制.大致上 ...

  7. Lua的多任务机制——协程(coroutine)

    并发是现实世界的本质特征,而聪明的计算机科学家用来模拟并发的技术手段便是多任务机制.大致上有这么两种多任务技术,一种是抢占式多任务(preemptive multitasking),它让操作系统来决定 ...

  8. Unity协程Coroutine使用总结和一些坑

    原文摘自 Unity协程Coroutine使用总结和一些坑 MonoBehavior关于协程提供了下面几个接口: 可以使用函数或者函数名字符串来启动一个协程,同时可以用函数,函数名字符串,和Corou ...

  9. 【Unity】协程Coroutine及Yield常见用法

    最近学习协程Coroutine,参考了别人的文章和视频教程,感觉协程用法还是相当灵活巧妙的,在此简单总结,方便自己以后回顾.Yield关键字的语意可以理解为“暂停”. 首先是yield return的 ...

随机推荐

  1. Red Hat 6.5 Samba服务器的搭建(匿名访问,免登录)

    搭建Samba服务器是为了实现Linux共享目录之后,在Windows可以直接访问该共享目录. 现在介绍如何在红帽6.5系统中搭建Samba服务. 搭建Samba服务之前,yum源必须配置好,本地源和 ...

  2. ubuntu 14.04 下配置 Go 1.51

    1.最简单的直接的方式(不用设置GOROOT) - 下载 归档文件 并解压到  /usr/local/go/  - 设置环境变量 - 设置系统级的 gedit /etc/profile # 在最末尾加 ...

  3. MP3 Lame 转换 参数 设置(转)

    我们在对音频格式的转换中,打交道最多的就是MP3了.如果你能彻底玩转MP3,那么对你的音频创作和对其他音频格式的掌握会有很大的帮助.下面我们给大家介绍MP3制作软件:LAME 要制作出高音质的MP3靠 ...

  4. org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions:323) | Loading XML bean definitions from class path resource [

    今天遇到一个这样的错误,这个错误是说我的spring的框架的文档没有写正确.但是反复检查,文档没有错误,原因是我使用了自己只做的user library,而且使用了 下边的System library ...

  5. 使用JavaScript获取CSS伪元素属性

    我们可以通过DOM元素的 style 属性获取基本的CSS样式值, 但怎么获取CSS伪元素属性呢? 如下 // 获取 .element:before 的 color 值 var color = win ...

  6. 字节序(Endian),大端(Big-Endian),小端(Little-Endian)

    http://www.cppblog.com/tx7do/archive/2009/01/06/71276.html 在各种计算机体系结构中,对于字节.字等的存储机制有所不同,因而引发了计算机通信领域 ...

  7. memcached整理の基本使用

    memcached 客户端与服务器端的通信比较简单,使用的基于文本的协议,而不是二进制协议.(http 协议也是这样), 因此我们通过telnet 即可与memcached 作交互. # 格式teln ...

  8. memcached整理の编译

    memcached是一个自由&开放源码, 高性能,分布式的内存对象缓存系统. nosql相对于传统关系型数据库的"行与列",NoSQL 的鲜明特点为k-v 存储(memca ...

  9. [转发]Oauth 1.0 1.0a 和 2.0 的之间的区别有哪些?

    原文地址:http://www.zhihu.com/question/19851243

  10. 记一次艰苦卓绝的Discuz x3 论坛升级过程

    首先吐槽一下discuz 的官方论坛. 你要想下载到正确版本的discuz实在不容易找到. 有兴趣自己去看吧. 就是因为这个原因, 我本来想要安装x2.5版本(那时x3 还是Beta版本), 结果不小 ...