brpc源码解析(四)—— Bthread机制

article/2025/8/29 19:56:23

目录

  • 一、概述
  • 二、启动入口函数
  • 三、内部启动函数
  • 四、worker工作入口
  • 五、总结

Bthread是brpc用到的一个线程库,也是brpc的核心之一,默认情况下,包括用户代码在内的绝大部分代码都是运行在bthread里的,bthread也是brpc实现高性能的基石。

一、概述

bthread在官方文档里定义如下:

bthread是baidu-rpc使用的M:N线程库,目的是在提高程序的并发度的同时,降低编码难度,并在核数日益增多的CPU上提供更好的scalability, cache locality。”M:N“是指M个bthread会映射至N个pthread,一般M远大于N。由于linux当下的pthread实现(NPTL)是1:1的,M个bthread也相当于映射至N个LWP。
Goals
1.用户可以延续同步的编程模式,能很快地建立bthread,可以用多种原语同步。
2.bthread所有接口可以在pthread中被调用并有合理的行为,使用bthread的代码可以在pthread中正常执行。 能充分利用多核。
3.更好的cache locality,更低的延时。
NonGoals
1.提供pthread的兼容接口,只需链接即可使用。拒绝理由:bthread没有优先级,不适用于所有的场景,链接的方式容易使用户在不知情的情况下误用bthread,造成bug。
2.修改内核让pthread支持同核快速切换。拒绝理由:拥有大量pthread后,每个线程对资源的需求被稀释了,基于thread-local cache的代码效果都会很差,比如tcmalloc。而独立的bthread不会有这个问题,因为它最终还是被映射到了少量的pthread。

官方地定义很好地总结了bthread的设计理念,个人认为核心就是用户可以延续同步的编程模式,但获得优秀的并发,并且保持了作为用户态线程的合理的克制,虽然能在pthread运行但对pthread没有侵入性。关于bthread的官方文档非常详细,想要深入了解可以参考官方文档,这里着重介绍一下在实际使用过程中bthread的一些运行机制。

之所以要采用这么一种M:N的机制,是为了兼顾当前多核cpu以及调度竞争上,考虑两种极端情况,一是每个用户线程对应一个内核线程,如果是这种模型,对多核cpu的利用会很充分,但是调度成本(用户态内核态的切换)以及线程间的数据同步成本都比较高,而是所有的用户线程都在一个内核线程的情况,这种情况下调度成本和数据同步成本低,但很难利用多核cpu的能力,同时用户线程也容易block。所以M:N线程库bthread的主要思想就是,M 个bthread 可以运行在N个内核线程上,也就是有N个worker分别运行在N个pthread上,所有的bthread都是在worker上调度运行,woker运行完一个bthread后就会去队列里调度下一个bthread,既可以从当前worker的本地队列里调度,也可以从其他worker的队列里取,也就是所谓的work stealing机制,该机制也是bthread核心设计之一。

二、启动入口函数

作为一个线程库,用户最常用的自然是启动线程,bthread的启动入口函数有两个:
(1)bthread_start_urgent:让出当前worker立即执行新bthread。
(2)bthread_start_background:将要启动的bthread放入队列等待调度。
函数名也说明了各自的行为。函数声明如下:
在这里插入图片描述
函数定义如下:
在这里插入图片描述
可以看到,二者很类似,都是先去获取了一个TaskGroup指针类型的变量g,然后根据g是否为null执行不同的逻辑。这里就涉及到bthread的taskgroup的概念,taskgroup的字面意思是任务组,一个taskgroup对应一个worker,所有的taskgroup由一个task_control的单例控制。在task_group.cpp里,有一个__thread变量tls_task_group,该变量在bthread.cpp里和task_control.cpp里均通过extern方式共用,也就是有一个thread-local的全局变量bthread::tls_task_group:
在这里插入图片描述
这个tls变量很重要,表明当前线程所归属的taskgroup,如果为null,说明当前线程不是bthread。

在上述启动bthread的函数里,首先就会判断taskgroup是否为null,如果不为null,则表明当前就是bthread而且taskgroup指明了对应的taskgroup,在对应taskgroup(worker)执行新bthread的启动即可,区别就是bthread_start_urgent调用内部的start_foreground,而bthread_start_background调用内部的start_background,否则属于在非worker上新启bthread,这个场景两个入口函数效果一样。

三、内部启动函数

bthread_start_urgent调用的TaskGroup::start_foreground函数核心部分如下:
在这里插入图片描述
在这里插入图片描述
这个函数里主要就是为要执行的任务新建taskmeta并对各种变量赋值,最重要的部分是fn和arg的赋值,然后最终直接调度执行。

而start_background和start_foreground最大的区别在于不是直接调度执行,如下:
在这里插入图片描述
REMOTE是函数模板参数,表明是否是从worker启动,为false说明不是远程,也就是是从worker启动。上面bthread_start_background直接调用start_foreground用的参数就是false,因为是从worker启动的。这个参数决定了调用ready_to_run_romote还是ready_to_run,二者分别如下:
在这里插入图片描述
在这里插入图片描述
二者的主要区别是对于来自非worker的bthread,放入_remote_rq队列,来自worker的放入_rq队列,总的来说是一个把任务加入队列然后调用signal按需唤醒woker的过程。调度顺序上,本地队列_rq的优先级比_remote_rq高,而且_rq是wait-free的,_remote_rq是用mutex保护的。

入口函数bthread_start_urgent或者bthread_start_background如果发现taskgroup是为null,则说明调用方不是在bthread里,这个时候去调用的start_from_non_worker函数如下:
在这里插入图片描述
该函数里会首先检查是否已经有task_control单例了,如果有说明其他地方已经建立过bthread了,也就已经启动了一定数量的taskgroup,如果没有说明是首次启动bthread,需要创建,new taskcontrol后会执行taskcontrol的init,核心就是用pthread启动指定数量的worker,如下:
在这里插入图片描述
得到taskcontrol单例后,用taskcontrol选取一个taskgroup,新建bthread进行调度。

上图里worker_thread函数如下:
在这里插入图片描述
先是调用create_group新建并初始化task_group,随后调用run_main_task,也就是worker的工作入口

四、worker工作入口

run_main_task的核心就是不断循环等待可以执行的bthread,包括去其他的woker steal,然后执行。如下:
在这里插入图片描述在这里插入图片描述
一旦拿到了可以执行的任务,则调用sched_to进行执行,里面是一些context的切换后执行之类的底层操作。前面提到了,如果在一个bthread里执行bthread_start_urgent,会调用TaskGroup::start_foreground,里面也是调用TaskGroup::sched_to立即让出当前worker。

上面调用的TaskGroup::sched_to函数如下:
在这里插入图片描述
根据传入的next_tid取出对应bthread的meta信息,如果对应meta的stack为空,说明这是一个新建的bthread,则会调用get_stack从一个object pool类型的资源池里取出stack对象赋给bthread,object pool继承自resource pool。get_stack函数如下:
在这里插入图片描述注意get_stack所用的参数:get_stack(next_meta->stack_type(), task_runner),第一个参数是stack类型,主要是按大小分为了好几种,第二个task_runner则是真正的用户函数的入口函数,task_runner内部核心代码如下:
在这里插入图片描述
m->fn(m-arg)就是使用启动bthread时提供的用户函数和对应参数进行调用。这个task_runner经过层层调用最终会作为一个叫做bthread_make_fcontext的汇编实现的函数的参数,该函数真正构造一个从taskrunner开始执行的stack,如下:
在这里插入图片描述
确保stack就绪后再调用内部的另一个void TaskGroup::sched_to(TaskGroup** pg, TaskMeta* next_meta)重载去执行切换操作。这个函数里比较长,核心部分如下:
在这里插入图片描述
切换threadlocal变量
在这里插入图片描述
进行堆栈的切换,也是bthread切换最关键的部分,jump_stack函数如下:
在这里插入图片描述
调用的是bthread_jump_fcontext,和bthread_jump_fcontext一样也是由汇编实现的,真正的去操作寄存器等完成线程切换。

五、总结

这篇文章介绍了bthread主要的启动和调度过程。除了这些,bthread还实现了butex,提供了类似pthread的同步原语,同时也有和pthread类似的bthread_join接口和tls支持接口等,总的来说接口和pthread很类似,同时因为bthread是跑在pthread里的,也支持在bthread里调用阻塞的pthread接口直接阻塞worker,具体的可以参照官方文档和注释很清晰的源码,这里不再赘述。


http://chatgpt.dhexx.cn/article/RYWCPlng.shtml

相关文章

Springboot集成Brpc

本文代码可在总结处自取。 1、为什么要写这篇文章 最近自己做的业务在和C团队对接,双方需要指定接口与传输协议。原本是直接使用http协议传输json数据,对双方来说都比较简单可接受。但是json数据传输效率实在令人堪忧,导致我们不得不另寻其道…

brpc源码学习(六)- brpc server 端整体流程

brpc的使用比较容易上手,以官方demo为例,因为brpc的数据序列化依赖protobuf,所以首先需要定义个proto 然后继承EchoService并实现Echo方法 然后是整体流程 启动还是比较简单的,定义server,AddService,然后S…

brpc源码解析(一)—— rpc服务添加以及服务器启动主要过程

目录 1.往Server里添加Service(业务代码)2.设置服务器参数3.启动服务器 平时的工作用到了baidu-rpc搭建rpc服务,作为戈君大神的大作,在没有开源的时候,这个c 的rpc框架在厂内就已经好评颇多,无论是性能、文…

brpc初步学习

一.BRPC介绍 BRPC百度开源的一个rpc框架,它具有以下特性: 基于protobuf接口的RPC框架,也提供json等其他数据格式的支持囊括baidu内部所有RPC协议,支持多种第三方协议模块化设计,层次清晰,很容易添加自定义…

brpc介绍、编译与使用

brpc又称为baidu-rpc,是百度开发一款“远程过程调用”网络框架。目前该项目已在github上开源——https://github.com/brpc/brpc。(转载请指明出于breaksoftware的csdn博客) 据目前公开的资料,我们发现百度内部从2010年开始&#x…

NB-IOT与物联网

1. 物联网的技术格局 短距离(智能家居/穿戴等) --- zigbee, wifi, BLE 长距离 (LPWA 低功耗广域) --- LORA, NB-IOT 关于LORA大致了解了一下情况 . Lora 其实已经是一个很成熟的技术方案. 国外已经大范围使用,国内也有不少公司在基于LORA运营物联网系统. LORA的系统结构…

lora和nbiot的相同点,它们之间有何区别和联系?

在物联网无线数据传输中,有诸多方式可以选择,包括蓝牙、WIFI、FSK、ASK/OOK、Lora、Zigbee、NB-iot、Z-Wave.等, 其中lora 和NBIot 是自2016年来比较热门的两个无线通讯方式。 我们今天就和大家简单的聊聊Lora 和NBiot。 我是在2016年接触…

NB-IOT开发|nbiot开发教程《三》AT指令类模组驱动-STM32实现AT指令状态机

嵌入式开发中我们要时刻保持代码的高效与整洁看之前,先点赞 好习惯,要养成 一、前言 嵌入式开发中我们要时刻保持代码的高效与整洁。在第一节中“NB-IOT开发|nbiot开发教程《一》AT指令类模组驱动解析”我们说到AT指令模组最好的驱动-状态机。本节我们就…

基于华为云IOT平台实现多节点温度采集(STM32+NBIOT)

一、前言 当前的场景是,在高速公路上部署温度采集设备,在高速路地表安装温度检测传感器,检测当前路段的路面实际温度。一段高速路上有多个地点需要采集温度数据。 采集温度数据需要上传到云平台进行数据存储,并且通过可视化界面展示温度变化曲线,支持查询最近几天的温度信…

NB-IoT的优势是什么?

NB-IoT的优势 : • 强链接:在同一基站的情况下,NB-IoT可以比现有无线技术提供50-100倍的接入数。一个扇区能够支持10万个连接,支持低延时敏感度、超低的设备成本、低设备功耗和优化的网络架构。举例来说,受限于带宽&a…

MN316_OPEN(NBIOT)物联网模块环境搭建

因为项目的需要,这里要使用NBIOT,踩了一些坑,这里总结一下! 编译 官方给的SDK如下: 按照说明,在该目录下直接运行如下指令:".\build.bat dlvs_h0 demo"即可成功编译,但是我编译的时候不成功,报错如下: 最后发现是因为我的目录太深的原因造成的,把"MN316_Op…

stm32毕业设计 NBIOT远程通信系统

文章目录 1 简介2 NBIOT 简介2.1 NBIOT 的特点2.2 NBIOT 的优点2.3 NBIOT能做什么 NBIOT 模块使用4 实现效果5 STM32 驱动NBIOT模块6 最后 1 简介 Hi,大家好,NBIOT是近几年不比较火的远程通信模块,是物联网的重要技术,今天学长向…

NB-IoT技术实战开发 ----- NB-IoT介绍

一.1------初识NB-IoT 1、NB-IoT介绍2、 物联网技术发展2.1有线物联网2.2 无线网络网 3、为什么需要NB-IOT4、NB-IOT优势5、NB-IOT解决方案亮点和价值5.1 广覆盖5.2 低功耗5.3低成本5.4 大连接 6、NB-IOT的应用1.智能抄表2.智能停车3.宠物跟踪4.else 1、NB-IoT介绍 NB-----Na…

【物联网】LoRa vs NBIoT

LoRa (Long Range) VS NB-IoT(Narrow Band Internet of Things) LoRa和NB-IoT是什么 通常物联网设备分为三类: 无需移动性,大数据量,需较宽频段;移动性强&#xff0…

物联网协议之NBIOT

什么是NBIOT 在物联网行业目前常用的网络通信技术主要有以下这些: nbiot属于一种LTE网络,LTE网络是目前主流的通信网络,覆盖完整、技术成熟,未来大量物联网设备都需要在LTE网络中实现通讯功能。Cat.X这个值是用来衡量用户终端设…

浅谈NBIOT

一、什么是NBIOT? 1、概念 窄带物联网(Narrow Band Internet of Things, NB-IoT),NB-IoT构建于蜂窝网络,只消耗大约180KHz的带宽,使用License频段,可采取带内、保护带或独立载波等三种部署方式…

【物联网毕设基础】NBIOT 窄带物联网

文章目录 1 简介2 NBIOT简介3NB的型号介绍3.1 BC95:3.2 BC35:3.3 BC28:3.4 BC26:3.5 BC20:3.6 BC30: 4 NB物联网卡5 OpenCPU6 BC260模块详解6.1 基本性能6.2 引脚介绍6.3 模块供电 7 其他注意点8 最后 1 简介 Hi&…

NB-IoT学习笔记 —— NB-IoT介绍

一、简介 NB-IoT 是指窄带物联网(Narrow Band Internet of Things)技术,是一种低功耗广域(LPWA)网络技术标准,基于蜂窝技术,用于连接使用无线蜂窝网络的各种智能传感器和设备,聚焦于…

淘宝客解析url优惠链接获取商品ID

淘宝客解析商品链接获取PID 优惠链接都有一个e参数,提取e参数,直接解析e参数就可以获取推广链接的商品ID; 这是一个优惠推广链接:https://uland.taobao.com/coupon/edetail?ed4tkoUeRofIN%2BoQUE6FNzDiOaI9VHkxMoEVLjjyR2S%2Bki3b8ti%2Bp7j…

ANSI/CAN/UL 1973:2022 固定和运动辅助电源用电池安规要求-最新的英文2022完整版{135页}

ANSI/CAN/UL 1973:2022 Batteries for Use in Stationary andMotive Auxiliary Power Applications 固定和运动辅助电源用电池 UL1973-2022(February25,2022).pdf-其它文档类资源-CSDN下载UL1973-2022(February25,2022).pdf更多下…