tbox的协程实现,是stackfull模式的,需要指定独立堆栈和协程函数,目前暂时还不能像golang那样实现堆栈的动态增长,之后会对其进行支持。

目前提供下面一些功能特性:

1. 提供yield切换调度支持,这个是必须的哈
2. 提供suspend(挂起)/resume(恢复)协程接口,不同于yield的是,被suspend后,如果不显示调用resume恢复它,是永远不会被调度到的
3. 提供sleep等待接口支持
4. 提供io调度支持,支持socket等io等待(内部使用epoll, poll, kqueue, select, poll等接口调度)
5. 原生支持stream,socket,http等模块的协程支持,可与线程进行无缝切换
6. 提供channel同道,进行协程间交互通信
7. 提供lock,semaphore等接口

这里主要讲讲,基础的切换调度如何使用。。

yield切换

这个的使用非常简单,直接上代码吧,嘿嘿。。

static tb_void_t switchfunc(tb_cpointer_t priv)
{
// 获取传入的参数
tb_size_t count = (tb_size_t)priv;
while (count--)
{
// 打印当前协程id
tb_trace_i("[coroutine: %p]: %lu", tb_coroutine_self(), count); // 让出当前协程,进行切换
tb_coroutine_yield();
}
}
tb_int_t main(tb_int_t argc, tb_char_t** argv)
{
// 初始化tbox
if (!tb_init(tb_null, tb_null)) return -1; // 初始化一个调度器实例
tb_co_scheduler_ref_t scheduler = tb_co_scheduler_init();
if (scheduler)
{
// 开启一个协程,传递switchfunc切换函数和参数10,最后一个参数指定栈大小,传0使用默认值
tb_coroutine_start(scheduler, switchfunc, (tb_cpointer_t)10, 0); // 开启协程,使用指定的栈大小:8192
tb_coroutine_start(scheduler, switchfunc, (tb_cpointer_t)10, 8192); /* 运行调用,开始运行里面的所有协程
*
* 第二个参数指定是否启用独占模式,这个稍后细讲
*/
tb_co_scheduler_loop(scheduler, tb_true); // 退出调度器
tb_co_scheduler_exit(scheduler);
} // 退出tbox
tb_exit();
}

所有协程执行完后,就会从loop调用处返回,当然在协程函数内部也是可以嵌套开启新协程的

这个时候第一个参数就不需要显示指定scheduler了,传tb_null表示在当前调度器环境中开新协程,例如:

static tb_void_t switchfunc2(tb_cpointer_t priv)
{
// ..
}
static tb_void_t switchfunc(tb_cpointer_t priv)
{
// 在当前协程函数内,开启一个新协程
tb_coroutine_start(tb_null, switchfunc2, tb_null, 0); // 获取传入的参数
tb_size_t count = (tb_size_t)priv;
while (count--)
{
// 让出当前协程,进行切换
tb_coroutine_yield();
}
}

独占模式

上面的代码中提到的独占模式,需要特殊说明下,一般情况下,传tb_false到loop()中,不启用此模式是最为稳妥的。

因为这样每个scheduler对应的线程都会在Tls中维护自己的scheduler引用,使得协程中所有操作,都回去访问当前线程tls对应的独立scheduler,互不干涉。

这个在存在多个scheduler的情况,尤为重要,当时这样多少会有些tls操作上的性能损耗,像server端一般只有一个scheduler的情况下,就没必要放到独立tls中去了

可以传入tb_true启用独占模式,告诉tb_co_scheduler_loop(),我当前不需要tls维护,只需要一个全局scheduler变量来维护就行了

这样的话,性能会提升一些,因此在只有一个scheduler存在的情况下,启用独占效率会高些。。

sleep等待

tbox的tb_sleeptb_msleep()接口,是可以原生支持协程的,在协程外就是线程等待,在协程内就是协程等待。

当然也可以直接使用协程的接口:tb_coroutine_sleep()

例如:

static tb_void_t sleepfunc(tb_cpointer_t priv)
{
while (1)
{
// 等待10ms,切换到其他协程,直到10ms后才会切换回来继续执行
tb_msleep(10);
}
}

resume/suspend接口

挂起域恢复,跟yield的区别就是,被suspend挂起的协程,默认是不会被切换调度回来的,除非执行resume恢复它。

因此这两个接口是成对使用的,像sleep,lock和semaphore的内部实现,也是基于此套接口。

这两个接口还有个功能,就是可以在两个协程间,更加快速方便的传递一些参数数据,进行交互,而不需要channel支持。。

例如:

static tb_void_t resumefunc(tb_cpointer_t priv)
{
// 获取suspend协程引用
tb_coroutine_ref_t coroutine = (tb_coroutine_ref_t)priv; /* 恢复suspend协程,传递参数"hello suspend!"给suspend()作为其返回值
*
* retval为suspend()中传入的参数:"hello resume!"
*/
tb_char_t const* retval = tb_coroutine_resume(coroutine, "hello suspend!");
}
static tb_void_t suspendfunc(tb_cpointer_t priv)
{
// 开启一个恢复协程,传入当前协程引用
tb_coroutine_start(tb_null, resumefunc, tb_coroutine_self(), 0); /* 挂起当前协程,传递参数"hello resume!"给resume()作为其返回值
*
* retval为resume()中传入的参数:"hello suspend!"
*/
tb_char_t const* retval = tb_coroutine_suspend("hello resume!");
}

当然,如果不需要交互数据,那么只需要传tb_null就行了。。


个人主页:TBOOX开源工程

原文出处:http://tboox.org/cn/2016/10/29/coroutine-switch/

tbox协程使用之切换与等待的更多相关文章

  1. 并发异步编程之争:协程(asyncio)到底需不需要加锁?(线程/协程安全/挂起/主动切换)Python3

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_208 协程与线程向来焦孟不离,但事实上是,线程更被我们所熟知,在Python编程领域,单核同时间内只能有一个线程运行,这并不是什么 ...

  2. GJM : 进程、线程和协程的理解

    感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...

  3. Queue、进程、线程、协程

    参考博客地址 http://www.cnblogs.com/alex3714/articles/5230609.html 1.python GIL全局解释器锁 python调用的操作系统的原生线程,当 ...

  4. 写个百万级别full-stack小型协程库——原理介绍

    其实说什么百万千万级别都是虚的,下面给出实现原理和测试结果,原理很简单,我就不上图了: 原理:为了简单明了,只支持单线程,每个协程共享一个4K的空间(你可以用堆,用匿名内存映射或者直接开个数组也都是可 ...

  5. Python 协程总结

    Python 协程总结 理解 协程,又称为微线程,看上去像是子程序,但是它和子程序又不太一样,它在执行的过程中,可以在中断当前的子程序后去执行别的子程序,再返回来执行之前的子程序,但是它的相关信息还是 ...

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

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

  7. 再议Python协程——从yield到asyncio

    协程,英文名Coroutine.前面介绍Python的多线程,以及用多线程实现并发(参见这篇文章[浅析Python多线程]),今天介绍的协程也是常用的并发手段.本篇主要内容包含:协程的基本概念.协程库 ...

  8. Golang 之协程详解

    转自:https://www.cnblogs.com/liang1101/p/7285955.html 一.Golang 线程和协程的区别 备注:需要区分进程.线程(内核级线程).协程(用户级线程)三 ...

  9. 协程与Epoll的配合

    想快速了解协程与网络调用的原来么,那么请赶紧关闭本页,因为下面都是在扯淡. 这几天是端午假期,第一天大算照着网上一大堆基于ucontext来写协程的文章自己也写一个简单的协程实现.于是第一天我就开始动 ...

随机推荐

  1. 微信JS-SDK选择图片遇到的坑

    微信JS-SDK选择图片遇到的坑 有个需求要在微信企业号里面做开发,有个功能是选择图片,使用input标签肯定是不管用了,Android手机上不能多选,所以使用了微信的JS-SDK提供的相关API,这 ...

  2. 最长回文子序列/最长回文子串(DP,马拉车)

    字符子串和字符子序列的区别 字符字串指的是字符串中连续的n个字符:如palindrome中,pa,alind,drome等都属于它的字串 而字符子序列指的是字符串中不一定连续但先后顺序一致的n个字符: ...

  3. 总结const、readonly、static三者的区别【收藏、转载】20190614

    总结const.readonly.static三者的区别 const:静态常量,也称编译时常量(compile-time constants),属于类型级,通过类名直接访问,被所有对象共享! a.叫编 ...

  4. SIGINT、SIGQUIT、 SIGTERM、SIGSTOP区别

    2) SIGINT程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程. 3) SIGQUIT和SIGINT类似, 但由QUIT字符(通 ...

  5. NTP时间服务器构建

    搭建一个NTP服务器,为整个网络环境中的所有主机提供时间校准服务,具体如下: - 部署一台NTP时间服务器 - 设置时间服务器上层与0.centos.pool.ntp.org同步 - 设置本地服务器层 ...

  6. PHP: thinkPHP踩坑记录(实现API接口以及处理莫名其妙的500问题)

    因为各种原因开始学习PHP,并且要在两周内能够对PHP项目进行二次开发,还好PHP够简单,至少入门很简单,很快就接触thinkPHP框架. 在了解了路由匹配视图的规则之后,开始着手尝试编写API接口, ...

  7. 【学习】006数据交换格式与SpringIOC底层实现

    课程目标 XML和JSON Java反射机制 手写SpringIOC 什么是数据交换格式 客户端与服务器常用数据交换格式xml.json.html 数据交换格式用场景 移动端(安卓.IOS)通讯方式采 ...

  8. 24.mongodb可视化工具部署——2019年12月19日

    2019年10月09日17:05:54 教程链接:https://blog.csdn.net/qq_32340877/article/details/79142129 项目名:adminMongo g ...

  9. Rabbit给单独的消息设置超时

    /** * 发送消息 * @param user */@RequestMapping(value = prefix+"/setRabbitMessage", method = Re ...

  10. HDU 5386 Cover

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5386 题目大意:给一个初始矩阵(n×n).一个目标矩阵(n×n)和m个操作,要求找到一种操作顺序,使初 ...