由于brpc中引入了bthread,如果在bthread中使用了mutex,那么将会挂起当前pthread,导致该bthread_worker无法执行其他bthread,因此类似pthread和futex的关系,brpc引入butex来实现bthread粒度的挂起和唤醒。

首先看下butex中使用到的FastPthreadMutex,FastPthreadMutex是基于futex实现的pthread粒度的锁,当竞争不激烈时,lock和unlock操作都是通过修改一个用户态的atomic来实现,只有当竞争激烈的时候才会陷入内核进行挂起和wake。不过互斥锁也是这么实现的,不是太理解重新实现一个的目的…

如果开启了BTHREAD_USE_FAST_PTHREAD_MUTEX宏定义,使用的是FastPthreadMutex,否则使用pthread_mutex_t。
首先看下lock方法

首先尝试修改locked这个atomic,如果发现锁没被占用,那么直接返回,否则调用lock_contended方法。注意这里使用了memory_order_acquire的memory order,和lock中的release形成syncwith关系,保证了当前线程获得锁之后能看到上个线程在释放锁之前对内存的修改。

当发现当前锁被占用时,通过系统调用futex_wait_private将当前线程挂起到whole这个atomic对应的队列中。

unlock方法通过futex_wake_private唤醒whole对应队列中的一个pthread,如上所述,这里使用release保证当前线程对内存的修改能被后续竞争到锁的线程看到。

然后看下butex,butex的实现类似futex。其中ButexWaiterList是一个链表,保存了在该butex上挂起的bthread或pthread。
waiter_lock即上述的锁。因为butex_wait时会比较atomic是否为expect_value,如果相等,那么将会挂起当前bthread至等待队列。如果判断是否相等和挂起这两个操作不在同一个临界区,那么有可能在判断之后但是挂起前已经执行过了butex_wake,将出现信号丢失问题,因此这里需要使用互斥锁。

然后看下butex_wait的过程

如果当前线程不是bthread_worker,那么直接调用butex_wait_from_pthread。
如果当前是bthread,那么直接在该bthread栈上创建ButexBthreadWaiter


然后设置remain,即pthread执行下一个bthread之前需要做的事情,设置完成后切到其他bthread上继续执行。664行为当前bthread恢复后开始执行的地方。然后看下remain,即wait_for_butex中做的工作。

首先在临界区中再次判断下expect_value是否等于butex中的value,如果相等,才把该waiter加入到butex的等待队列中;如果不相等,则将waiter重新加入到rq中等待调度。

然后是butex_wake的过程。
在该butex的等待队列中唤醒第一个ButexWaiter front,如果front是pthread,那么调用wakeup_pthread;
然后如果当前pthread是bthread_worker,那么直接让出当前bthread,直接执行被唤醒的bthread,如果当前pthread不是bthread_worker,那么就把当前bthread加入到某个task_group的remote_rq中。

brpc源码学习(一)-butex相关推荐

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

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

  2. brpc源码学习(五)-IOBuf

    目录 Block BlockRef IOBuf 主要api tls优化 IOPortal protobuf接口 首先放上官方介绍: brpc使用butil::IOBuf作为一些协议中的附件或http ...

  3. brpc源码学习(二)-bthread的创建与切换

    brpc引入m:n的线程模型,固定的内核线程调度运行大量的bthread以避免内核线程上下文切换带来的开销. bthread类似协程,即用户态线程,bthread的切换不会陷入内核,不会进行一系列内存 ...

  4. Shiro源码学习之二

    接上一篇 Shiro源码学习之一 3.subject.login 进入login public void login(AuthenticationToken token) throws Authent ...

  5. Shiro源码学习之一

    一.最基本的使用 1.Maven依赖 <dependency><groupId>org.apache.shiro</groupId><artifactId&g ...

  6. mutations vuex 调用_Vuex源码学习(六)action和mutation如何被调用的(前置准备篇)...

    前言 Vuex源码系列不知不觉已经到了第六篇.前置的五篇分别如下: 长篇连载:Vuex源码学习(一)功能梳理 长篇连载:Vuex源码学习(二)脉络梳理 作为一个Web前端,你知道Vuex的instal ...

  7. vue实例没有挂载到html上,vue 源码学习 - 实例挂载

    前言 在学习vue源码之前需要先了解源码目录设计(了解各个模块的功能)丶Flow语法. src ├── compiler # 把模板解析成 ast 语法树,ast 语法树优化,代码生成等功能. ├── ...

  8. 2021-03-19Tomcat源码学习--WebAppClassLoader类加载机制

    Tomcat源码学习--WebAppClassLoader类加载机制 在WebappClassLoaderBase中重写了ClassLoader的loadClass方法,在这个实现方法中我们可以一窥t ...

  9. jQuery源码学习之Callbacks

    jQuery源码学习之Callbacks jQuery的ajax.deferred通过回调实现异步,其实现核心是Callbacks. 使用方法 使用首先要先新建一个实例对象.创建时可以传入参数flag ...

最新文章

  1. C++ 泛型编程 -- 函数模版
  2. 清理SQL Server日志释放文件空间的终极方法
  3. 在EF中使用SQL执行简单高效的增删查操作
  4. datagrid如何获取一行数据中的某个字段值_SQL中常见的面试题
  5. 北京理工计算机 上机复试2000年
  6. autocad2022发布 autocad2022中文版新功能
  7. Qt——多语言程序设计
  8. win10系统ps3手柄蓝牙连接方法_ps3手柄怎么进入配对模式win10
  9. 企业生产现场中5S管理的应用
  10. Android开发需要学什么,技术实现
  11. 肾有多好,就有多年轻
  12. graphql入门使用-查询
  13. php usc2,CSDN 免积分下载原理
  14. php怎么判断qq内置浏览器,如何判断微信内置浏览器(JS PHP)
  15. java 对数和指数计算
  16. 【曹工杂谈】Maven底层容器Plexus Container的前世今生,一代芳华终落幕
  17. 项目管理中,要明确每个人的工作职责
  18. 三星 Galaxy S4 全面精简列表详解及三星KNOX所有组件。
  19. 小度和天猫精灵哪个好?这次我站小度
  20. 高频交易数据如何快速降频

热门文章

  1. Oracle中coalesce函数的用法
  2. CVE-2012-0003:Microsoft Windows Media Player winmm.dll MIDI 文件堆溢出漏洞调试分析
  3. 前端实现pdf在线预览
  4. 设计模式入门(王者荣耀之设计英雄篇)
  5. Oculus联合创始人Palmer Luckey:我不认为Facebook是VR的未来
  6. 关于保守与创新,核心竞争力与核心战略
  7. 鸿蒙3部曲先看哪部,星辰变是“鸿蒙”系列的作品,那“鸿蒙”系列到底有多少部曲?...
  8. 保安值班安排系统C语言课程设计
  9. ECSHOP去版权教程
  10. ABAPDEMOCALLTRANSACTION使用_SAP刘梦_新浪博客