当前位置: 首页 > news >正文

【服务器】fiber协程模块

fiber协程模块

以下是从sylar服务器中学的,对其的复习;

  • sylar的fiber协程模块是基于ucontext_t实现非对称协程

函数只有两个行为:调用与返回。一旦函数返回后,它在栈上所拥有的状态将被销毁。协程相比函数多了两个动作:挂起与恢复。当协程主动挂起时,它的控制权将转交给另一个协程,这时它所拥有的状态仍被保留着,另一个协程获取控制权后,在将来某个时间点也可能选择挂起,从而使原协程的控制权得以恢复,一旦协程像函数一样返回,它所拥有的状态将被销毁。

协程是能暂停执行以在之后恢复的函数。

同样是单线程环境下,协程的yield和resume一定是同步进行的,一个协程的yield,必然对应另一个协程的resume,因为线程不可能没有执行主体。并且,协程的yield和resume是完全由应用程序来控制的。与线程不同,线程创建之后,线程的运行和调度也是由操作系统自动完成的,但协程创建后,协程的运行和调度都要由应用程序来完成,就和调用函数一样,所以协程也被称为用户态线程。

所谓创建协程,其实就是把一个函数包装成一个协程对象,然后再用协程的方式把这个函数跑起来;所谓协程调度,其实就是创建一批的协程对象,然后再创建一个调度协程,通过调度协程把这些协程对象一个一个消化掉(协程可以在被调度时继续向调度器添加新的调度任务);所谓IO协程调度,其实就是在调度协程时,如果发现这个协程在等待IO就绪,那就先让这个协程让出执行权,等对应的IO就绪后再重新恢复这个协程的运行;所谓定时器,就是给调度协程预设一个协程对象,等定时时间到了就恢复预设的协程对象。

ucontext_t接口

// 上下文结构体定义
typedef struct ucontext_t {// 当前上下文结束后,下一个激活的上下文对象的指针,只在当前上下文是由makecontext创建时有效struct ucontext_t *uc_link;// 当前上下文的信号屏蔽掩码sigset_t          uc_sigmask;// 当前上下文使用的栈内存空间,只在当前上下文是由makecontext创建时有效stack_t           uc_stack;// 平台相关的上下文具体内容,包含寄存器的值mcontext_t        uc_mcontext;...
} ucontext_t;// 获取当前的上下文
int getcontext(ucontext_t *ucp);// 恢复ucp指向的上下文,这个函数不会返回,而是会跳转到ucp上下文对应的函数中执行,相当于变相调用了函数
int setcontext(const ucontext_t *ucp);// 修改由getcontext获取到的上下文指针ucp,将其与一个函数func进行绑定,支持指定func运行时的参数,
// 在调用makecontext之前,必须手动给ucp分配一段内存空间,存储在ucp->uc_stack中,这段内存空间将作为func函数运行时的栈空间,
// 同时也可以指定ucp->uc_link,表示函数运行结束后恢复uc_link指向的上下文,
// 如果不赋值uc_link,那func函数结束时必须调用setcontext或swapcontext以重新指定一个有效的上下文,否则程序就跑飞了
// makecontext执行完后,ucp就与函数func绑定了,调用setcontext或swapcontext激活ucp时,func就会被运行
void makecontext(ucontext_t *ucp, void (*func)(), int argc, ...);// 恢复ucp指向的上下文,同时将当前的上下文存储到oucp中,
// 和setcontext一样,swapcontext也不会返回,而是会跳转到ucp上下文对应的函数中执行,相当于调用了函数
int swapcontext(ucontext_t *oucp, const ucontext_t *ucp);

sylar协程模块设计

sylar使用非对称协程模型,也就是子协程只能和线程主协程切换,而不能和另一个子协程切换,并且在程序结束时,一定要再切回主协程,以保证程序能正常结束

sylar对每个协程,设计了6种状态

/*** @brief 协程状态*/
enum State {/// 初始化状态INIT,/// 暂停状态HOLD,/// 执行中状态EXEC,/// 结束状态TERM,/// 可执行状态READY,/// 异常状态EXCEPT
};

fiber类包含以下成员变量

/// 协程id
uint64_t m_id        = 0;
/// 协程栈大小
uint32_t m_stacksize = 0;
/// 协程状态
State m_state        = READY;
/// 协程上下文
ucontext_t m_ctx;
/// 协程栈地址
void *m_stack = nullptr;
/// 协程入口函数
std::function<void()> m_cb;

定义了两个全局静态变量,用于生成协程id和统计当前的协程数

/// 全局静态变量,用于生成协程id
static std::atomic<uint64_t> s_fiber_id{0};
/// 全局静态变量,用于统计当前的协程数
static std::atomic<uint64_t> s_fiber_count{0};

以下两个线程局部变量用于保存协程上下文信息

/// 线程局部变量,当前线程正在运行的协程
static thread_local Fiber *t_fiber = nullptr;
/// 线程局部变量,当前线程的主协程,切换到这个协程,就相当于切换到了主线程中运行,智能指针形式
static thread_local Fiber::ptr t_thread_fiber = nullptr;

构造函数
带参数的构造函数用于构造子协程,初始化子协程的ucontext_t上下文和栈空间,要求必须传入协程的入口函数,以及可选的协程栈大小。不带参的构造函数用于初始化当前线程的协程功能,构造线程主协程对象

/*** @brief 构造函数* @attention 无参构造函数只用于创建线程的第一个协程,也就是线程主函数对应的协程,* 这个协程只能由GetThis()方法调用,所以定义成私有方法*/
Fiber::Fiber(){SetThis(this);m_state = RUNNING;if (getcontext(&m_ctx)) {SYLAR_ASSERT2(false, "getcontext");}++s_fiber_count;m_id = s_fiber_id++; // 协程id从0开始,用完加1SYLAR_LOG_DEBUG(g_logger) << "Fiber::Fiber() main id = " << m_id;
}/*** @brief 构造函数,用于创建用户协程* @param[] cb 协程入口函数* @param[] stacksize 栈大小,默认为128k*/
Fiber::Fiber(std::function<void()> cb, size_t stacksize): m_id(s_fiber_id++), m_cb(cb) {++s_fiber_count;m_stacksize = stacksize ? stacksize : g_fiber_stack_size->getValue();m_stack     = StackAllocator::Alloc(m_stacksize);if (getcontext(&m_ctx)) {SYLAR_ASSERT2(false, "getcontext");}m_ctx.uc_link          = nullptr;m_ctx.uc_stack.ss_sp   = m_stack;m_ctx.uc_stack.ss_size = m_stacksize;makecontext(&m_ctx, &Fiber::MainFunc, 0);SYLAR_LOG_DEBUG(g_logger) << "Fiber::Fiber() id = " << m_id;
}/*** @brief 返回当前线程正在执行的协程* @details 如果当前线程还未创建协程,则创建线程的第一个协程,* 且该协程为当前线程的主协程,其他协程都通过这个协程来调度,也就是说,其他协程* 结束时,都要切回到主协程,由主协程重新选择新的协程进行resume* @attention 线程如果要创建协程,那么应该首先执行一下Fiber::GetThis()操作,以初始化主函数协程*/
Fiber::ptr GetThis(){if (t_fiber) {return t_fiber->shared_from_this();}Fiber::ptr main_fiber(new Fiber);SYLAR_ASSERT(t_fiber == main_fiber.get());t_thread_fiber = main_fiber;return t_fiber->shared_from_this();
}

协程原语的实现,挂起和恢复

/*** @brief 将当前协程切换到运行状态(与调度协程)* @pre getState() != EXEC* @post getState() = EXEC*/
void Fiber::swapIn() {SetThis(this);SYLAR_ASSERT(m_state != EXEC);m_state = EXEC;if(swapcontext(&Scheduler::GetMainFiber()->m_ctx, &m_ctx)) {SYLAR_ASSERT2(false, "swapcontext");}
}/*** @brief 将当前协程切换到后台(与调度协程)*/
void Fiber::swapOut() {SetThis(Scheduler::GetMainFiber());if(swapcontext(&m_ctx, &Scheduler::GetMainFiber()->m_ctx)) {SYLAR_ASSERT2(false, "swapcontext");}
}/*** @brief 将当前线程切换到执行状态(与主协程)* @pre 执行的为当前线程的主协程*/
void Fiber::call() {SetThis(this);m_state = EXEC;SYLAR_LOG_ERROR(g_logger) << getId();if(swapcontext(&t_threadFiber->m_ctx, &m_ctx)) {SYLAR_ASSERT2(false, "swapcontext");}
}/*** @brief 将当前线程切换到后台(与主协程)* @pre 执行的为该协程* @post 返回到线程的主协程*/
void Fiber::back() {SetThis(t_threadFiber.get());if(swapcontext(&m_ctx, &t_threadFiber->m_ctx)) {SYLAR_ASSERT2(false, "swapcontext");}
}

协程入口函数

void Fiber::MainFunc() {Fiber::ptr cur = GetThis(); // GetThis()的shared_from_this()方法让引用计数加1SYLAR_ASSERT(cur);cur->m_cb(); // 这里真正执行协程的入口函数cur->m_cb    = nullptr;cur->m_state = TERM;auto raw_ptr = cur.get(); // 手动让t_fiber的引用计数减1cur.reset();raw_ptr->yield(); // 协程结束时自动yield,以回到主协程
}

协程的重置
重复利用已结束的协程,复用其栈空间,创建新协程

void Fiber::reset(std::function<void()> cb) {SYLAR_ASSERT(m_stack);SYLAR_ASSERT(m_state == TERM);m_cb = cb;if (getcontext(&m_ctx)) {SYLAR_ASSERT2(false, "getcontext");}m_ctx.uc_link          = nullptr;m_ctx.uc_stack.ss_sp   = m_stack;m_ctx.uc_stack.ss_size = m_stacksize;makecontext(&m_ctx, &Fiber::MainFunc, 0);m_state = READY;
}

相关文章:

【服务器】fiber协程模块

fiber协程模块 以下是从sylar服务器中学的&#xff0c;对其的复习&#xff1b; sylar的fiber协程模块是基于ucontext_t实现非对称协程 函数只有两个行为&#xff1a;调用与返回。一旦函数返回后&#xff0c;它在栈上所拥有的状态将被销毁。协程相比函数多了两个动作&#xf…...

SparkML

SparkML SparkML_lr_train &#xff1a;读取py处理后的train表用于训练&#xff0c;将训练模型保存好。 SparkML_lr_predict &#xff1a;读取训练好的模型&#xff0c;读取py处理后的test表用于预测。将预测结果写入normal_data中&#xff0c;根据id修改stream_is_normal的值。…...

实时定位与路径优化:跑腿App系统开发中的地理信息技术

本文将介绍如何使用地理信息技术实现实时定位和路径优化功能&#xff0c;以提高跑腿服务的效率。 实时定位 用户位置获取 # 示例&#xff1a;获取用户的实时位置 def get_user_location(user_id):# 使用GPS或网络定位技术获取用户的地理坐标# 返回经度和纬度信息return lon…...

Tomcat的HTTP Connector

https://tomcat.apache.org/tomcat-10.1-doc/config/http.html 一个Connector代表一个接收请求、返回响应的端点&#xff08;endpoint&#xff09;。 HTTP Connector 元素代表一个支持HTTP/1.1的Connector组件。一个这样的组件在服务端一个指定的TCP端口上监听连接。一个Serv…...

将Pytorch搭建的ViT模型转为onnx模型

本文尝试将pytorch搭建的ViT模型转为onnx模型。 首先将博主上一篇文章中搭建的模型ViT Vision Transformer超详细解析&#xff0c;网络构建&#xff0c;可视化&#xff0c;数据预处理&#xff0c;全流程实例教程-CSDN博客转存为.pth torch.save(model, my_vit_model.pth) 然…...

图神经网络(GNN)性能优化方案汇总,附37个配套算法模型和代码

图神经网络的表达能力对其性能和应用范围有着重要的影响&#xff0c;是GNN研究的核心问题和发展方向。增强表达能力是扩展GNN应用范围、提高性能的关键所在。 目前GNN的表达能力受特征表示和拓扑结构这两个因素的影响&#xff0c;其中GNN在学习和保持图拓扑方面的缺陷是限制表…...

国科大移动互联网考试资料(2023+2020+2018真题+答案)

老师王文杰。真题附加2022部分...

ModStart系统安全规范建议

1 不要使用弱密码 很多人为了系统管理方便&#xff08;或者是懒&#xff09;&#xff0c;经常会设置类似 123456、admin 这样的管理密码&#xff0c;这样的密码很容易被暴力软件扫描出来。 2 不要使用默认配置 默认的软件系统设置、默认的系统端口、默认的网站设置在发生漏洞…...

【漏洞复现】Django_debug page_XSS漏洞(CVE-2017-12794)

感谢互联网提供分享知识与智慧&#xff0c;在法治的社会里&#xff0c;请遵守有关法律法规 文章目录 1.1、漏洞描述1.2、漏洞等级1.3、影响版本1.4、漏洞复现1、基础环境2、漏洞分析3、漏洞验证 说明内容漏洞编号CVE-2017-12794漏洞名称Django_debug page_XSS漏洞漏洞评级影响范…...

Redis性能调优:深度剖析与示例解析

标题&#xff1a;Redis性能调优&#xff1a;深度剖析与示例解析 引言 Redis是一款强大的开源内存数据库&#xff0c;广泛应用于高性能系统。然而&#xff0c;为了充分发挥Redis的性能&#xff0c;需要进行合理的性能调优。本博客将深入介绍Redis性能调优的策略和示例&#xf…...

oracle查询前几条数据的方法

在Oralce中实现select top N&#xff1a;由于Oracle不支持select top 语句&#xff0c;所以在oracle中经常是用order by 跟rownum的组合来实现select top n的查询。 方法1&#xff1a; SELECT * FROM (SELECT * FROM EMP ORDER BY SAL DESC) WHERE ROWNUM < 5 --抽取处记录…...

c#弹性和瞬态故障处理库Polly

1. 重试&#xff08;Retry&#xff09; Policy .Handle<Exception>() //指定需要重试的异常类型 .Retry(2,(ex,count,context)> { //指定发生异常重试的次数Console.WriteLine($ "重试次数{count},异常{ex.Message}" ); }) …...

20231107-前端学习炫酷菜单效果和折叠侧边栏

炫酷菜单效果 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>炫酷菜单效果</title><…...

基于CLIP的图像分类、语义分割和目标检测

OpenAI CLIP模型是一个创造性的突破&#xff1b; 它以与文本相同的方式处理图像。 令人惊讶的是&#xff0c;如果进行大规模训练&#xff0c;效果非常好。 在线工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 3D…...

python爬虫(数据获取——selenium)

环境测试 from selenium import webdriverchromedriver_path r"C:\Program Files\Google\Chrome\Application\chromedriver.exe" driver webdriver.Chrome()url "https://www.xinpianchang.com/discover/article?fromnavigator" driver.get(url)drive…...

[wp]NewStarCTF 2023 WEEK5|WEB

前言:比赛是结束了&#xff0c;但我的学习还未结束&#xff0c;看看自己能复习几道题吧&#xff0c;第四周实在太难 Final 考点&#xff1a; ThinkPHP 5.0.23 RCE一句话木马上传SUID提权&#xff08;find&#xff09; 解题: 首先页面就给了ThinkPHP V5&#xff0c; 那无非考…...

未将对象引用设置到对象实例

环境 vs 2017 qt 5.13.0 qt-vs-addin 2.10 qt 项目打开的vs 2010 的项目 配置完成之后可以编译执行&#xff0c;但是新建qt 类提示 未将对象引用设置到对象实例 问题 插件的版本太高了使用低版本的&#xff0c;到qt 官网下载Index of /official_releases/vsaddin 下载q…...

网络的地址簿:Linux DNS服务的全面指南

1 dns 1.1 dns&#xff08;域名解析服务&#xff09;介绍 当访问 www.baidu.com 首先查询/etc/hosts&#xff0c;如果没有再去查询/etc/resolv.conf&#xff0c;还是没有就去查询域名服务器 关于客户端: /etc/resolv.conf ##dns指向文件 nameserver 172.25.254.20测试&…...

输电线路AR可视化巡检降低作业风险

随着现代工业的快速发展&#xff0c;各行业的一线技术工人要处理的问题越来越复杂&#xff0c;一些工作中棘手的问题迫切需要远端专家的协同处理。但远端专家赶来现场往往面临着专家差旅成本高、设备停机损失大、专业支持滞后、突发故障无法立即解决等痛点。传统的远程协助似乎…...

18. 四数之和

18. 四数之和 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a;错误经验吸取 原题链接&#xff1a; 18. 四数之和 https://leetcode.cn/problems/4sum/description/ 完成情况&#xff1a; 解题思路&#xff1a; /** * //HashMap只能记录…...

排序:堆排序(未完待续)

文章目录 排序一、 排序的概念1.排序&#xff1a;2.稳定性&#xff1a;3.内部排序&#xff1a;4.外部排序&#xff1a; 二、插入排序1.直接插入排序 二、插入排序堆排序 排序 一、 排序的概念 1.排序&#xff1a; 一组数据按递增/递减排序 2.稳定性&#xff1a; 待排序的序列…...

小米智能电视投屏方法

小米智能电视也提供了投屏功能。 使用遥控器&#xff0c;在应用中找到它&#xff0c;点击进入。 小米电视支持windows笔记本&#xff0c;macbook笔记本&#xff0c;iphone手机&#xff0c;安卓手机投屏。 windows笔记本投屏 在投屏应用中找到windows投屏&#xff0c;选中开…...

保外就医罪犯收到指定医院《罪犯病情诊断书》及检测、检查报告等其他医疗文书后,应当在规定时限内提交( ),或者受委托司法所审查。

需要查看详细试题题库及其参考答案的&#xff0c;请到&#xff08;题-海-舟&#xff09;里进行搜索查看。可搜试题题干或者搜索关键词&#xff0c;搜题的时候&#xff0c;先进行题目识别&#xff0c;能大大提高学习效率&#xff0c;感谢使用&#xff01; 保外就医罪犯收到指定…...

pytorh模型训练、测试

目录 1 导入数据集 2 使用tensorboard展示经过各个层的图片数据 3 完整的模型训练测试流程 使用Gpu训练的两种方式 使用tensorboard显示模型 模型训练测试 L1Loss函数 保存未训练模型或者已经训练完的模型 4 加载训练好的模型进行测试 1 导入数据集 import torch from torch.u…...

MySQL 8.0 Clone Plugin 详解

文章目录 前言1. 克隆插件安装2. 克隆插件的使用2.1 本地克隆2.2 远程克隆 3. 克隆任务监控4. 克隆插件实现4.1 Init 阶段4.2 File Copy4.3 Page Copy4.4 Redo Copy4.5 Done 5. 克隆插件的限制6. 克隆插件与 Xtrabackup 的异同7. 克隆插件相关参数 后记 前言 克隆插件&#xf…...

掌握未来技术趋势:深度学习与量子计算的融合

掌握未来技术趋势&#xff1a;深度学习与量子计算的融合 摘要&#xff1a;本博客将探讨深度学习与量子计算融合的未来趋势&#xff0c;分析这两大技术领域结合带来的潜力和挑战。通过具体案例和技术细节&#xff0c;我们将一睹这两大技术在人工智能、药物研发和金融科技等领域…...

京东数据分析:2023年9月京东笔记本电脑行业品牌销售排行榜

鲸参谋监测的京东平台9月份笔记本电脑市场销售数据已出炉&#xff01; 9月份&#xff0c;笔记本电脑市场整体销售下滑。鲸参谋数据显示&#xff0c;今年9月份&#xff0c;京东平台上笔记本电脑的销量将近59万&#xff0c;环比下滑约21%&#xff0c;同比下滑约40%&#xff1b;销…...

3 任务3 使用趋动云部署自己的stable-diffusion

使用趋动云部署自己的stable-diffusion 1 创建项目&#xff1a;2 初始化开发环境实例3 部署模型4 模型测试 1 创建项目&#xff1a; 1.进入趋动云用户工作台&#xff0c;选择&#xff1a;当前空间&#xff0c;请确保当前所在空间是注册时系统自动生成的空间。 a.非系统自动生成…...

C语言 memset

C语言memset函数详解_C 语言_脚本之家 (jb51.net) 注意是按照字节赋值的。int型变量&#xff0c;当赋值0时&#xff0c;是没有问题的&#xff0c;但是赋值1&#xff0c;却按照每个字节都赋值1&#xff0c;最终结果错误。 怎么解决呢&#xff1f; 不能使用memset么&#xff1…...

Windows安装svn命令

1、svn命令下载地址 https://www.visualsvn.com/downloads/; 2、安装svn命令 3、测试svn命令是否安装成功...