tbox协程使用之切换与等待
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_sleep
和tb_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协程使用之切换与等待的更多相关文章
- 并发异步编程之争:协程(asyncio)到底需不需要加锁?(线程/协程安全/挂起/主动切换)Python3
原文转载自「刘悦的技术博客」https://v3u.cn/a_id_208 协程与线程向来焦孟不离,但事实上是,线程更被我们所熟知,在Python编程领域,单核同时间内只能有一个线程运行,这并不是什么 ...
- GJM : 进程、线程和协程的理解
感谢您的阅读.喜欢的.有用的就请大哥大嫂们高抬贵手"推荐一下"吧!你的精神支持是博主强大的写作动力以及转载收藏动力.欢迎转载! 版权声明:本文原创发表于 [请点击连接前往] ,未经 ...
- Queue、进程、线程、协程
参考博客地址 http://www.cnblogs.com/alex3714/articles/5230609.html 1.python GIL全局解释器锁 python调用的操作系统的原生线程,当 ...
- 写个百万级别full-stack小型协程库——原理介绍
其实说什么百万千万级别都是虚的,下面给出实现原理和测试结果,原理很简单,我就不上图了: 原理:为了简单明了,只支持单线程,每个协程共享一个4K的空间(你可以用堆,用匿名内存映射或者直接开个数组也都是可 ...
- Python 协程总结
Python 协程总结 理解 协程,又称为微线程,看上去像是子程序,但是它和子程序又不太一样,它在执行的过程中,可以在中断当前的子程序后去执行别的子程序,再返回来执行之前的子程序,但是它的相关信息还是 ...
- Python并发编程协程(Coroutine)之Gevent
Gevent官网文档地址:http://www.gevent.org/contents.html 基本概念 我们通常所说的协程Coroutine其实是corporate routine的缩写,直接翻译 ...
- 再议Python协程——从yield到asyncio
协程,英文名Coroutine.前面介绍Python的多线程,以及用多线程实现并发(参见这篇文章[浅析Python多线程]),今天介绍的协程也是常用的并发手段.本篇主要内容包含:协程的基本概念.协程库 ...
- Golang 之协程详解
转自:https://www.cnblogs.com/liang1101/p/7285955.html 一.Golang 线程和协程的区别 备注:需要区分进程.线程(内核级线程).协程(用户级线程)三 ...
- 协程与Epoll的配合
想快速了解协程与网络调用的原来么,那么请赶紧关闭本页,因为下面都是在扯淡. 这几天是端午假期,第一天大算照着网上一大堆基于ucontext来写协程的文章自己也写一个简单的协程实现.于是第一天我就开始动 ...
随机推荐
- 微信JS-SDK选择图片遇到的坑
微信JS-SDK选择图片遇到的坑 有个需求要在微信企业号里面做开发,有个功能是选择图片,使用input标签肯定是不管用了,Android手机上不能多选,所以使用了微信的JS-SDK提供的相关API,这 ...
- 最长回文子序列/最长回文子串(DP,马拉车)
字符子串和字符子序列的区别 字符字串指的是字符串中连续的n个字符:如palindrome中,pa,alind,drome等都属于它的字串 而字符子序列指的是字符串中不一定连续但先后顺序一致的n个字符: ...
- 总结const、readonly、static三者的区别【收藏、转载】20190614
总结const.readonly.static三者的区别 const:静态常量,也称编译时常量(compile-time constants),属于类型级,通过类名直接访问,被所有对象共享! a.叫编 ...
- SIGINT、SIGQUIT、 SIGTERM、SIGSTOP区别
2) SIGINT程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程. 3) SIGQUIT和SIGINT类似, 但由QUIT字符(通 ...
- NTP时间服务器构建
搭建一个NTP服务器,为整个网络环境中的所有主机提供时间校准服务,具体如下: - 部署一台NTP时间服务器 - 设置时间服务器上层与0.centos.pool.ntp.org同步 - 设置本地服务器层 ...
- PHP: thinkPHP踩坑记录(实现API接口以及处理莫名其妙的500问题)
因为各种原因开始学习PHP,并且要在两周内能够对PHP项目进行二次开发,还好PHP够简单,至少入门很简单,很快就接触thinkPHP框架. 在了解了路由匹配视图的规则之后,开始着手尝试编写API接口, ...
- 【学习】006数据交换格式与SpringIOC底层实现
课程目标 XML和JSON Java反射机制 手写SpringIOC 什么是数据交换格式 客户端与服务器常用数据交换格式xml.json.html 数据交换格式用场景 移动端(安卓.IOS)通讯方式采 ...
- 24.mongodb可视化工具部署——2019年12月19日
2019年10月09日17:05:54 教程链接:https://blog.csdn.net/qq_32340877/article/details/79142129 项目名:adminMongo g ...
- Rabbit给单独的消息设置超时
/** * 发送消息 * @param user */@RequestMapping(value = prefix+"/setRabbitMessage", method = Re ...
- HDU 5386 Cover
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5386 题目大意:给一个初始矩阵(n×n).一个目标矩阵(n×n)和m个操作,要求找到一种操作顺序,使初 ...