brpc源码学习(三)- WorkStealingQueue

每个bthread_worker都有自己的work_stealing_queue,bthread_worker会从自己queue里pop数据进行处理,如果自己的queue为空,则尝试去其他bthread_worker的queue中steal,所以当前queue不会发生pop和push并发的情况;可能发生并发的情况为,steal和steal,steal和push,steal和pop;为了避免锁的开销,brpc设计了lock-free的WorkStealingQueue。

 

work stealing queue的push和pop在bottom侧,steal在top侧。

 

首先看下push,因为steal不会修改bottom,所以74行bottom用relax读就好,无需同步,而top会被其他bthread_worker修改,因此通过acquire可以看到其他线程release修改top前对内存做的修改;然后判断是否超过queue的容量限制;如果没有超过容量限制,那么在bottom位置写入新数据,并更新bottom;80行bottom的写入使用release是为了保证steal能看到bottom处的数据写入。

 

然后看下pop

通过relax得到的top快速判断是否为空。然后将bottom减一,为了保证同一元素不会既被pop,又被steal,所以加了seq_cst的fence,同steal配对,具体流程后面详述;然后获取top,如果top大于newb,说明queue空,此时需将bottom修改回去;然后将val设置为newb位置的数据;如果t != newb,说明队列中有不止一个数据,此时pop和steal不会竞争,因此直接返回;否则将产生竞争,如果此时top没有发生变化,即还等于t,那么说明此时没有发生steal,将top和bottom统一加一,pop的数据可用;如果top不等于t,那么说明发生了steal,此时需将bottom恢复,pop的数据不可用。

 

然后看下steal,为了能够看到push对buffer的修改,所以这里对bottom的读取使用了acquire,而top用acquire是为了看到pop里对内存的修改。

然后是一个do while循环,126行的seq_cst是为了和pop的98行配对;127行对bottom的acquire读是为了若126到127行之间push进来一个数据,如果不使用acquire可能会导致看到新的bottom,而没有看到新的数据的情况;然后设置val,cas读top,如果没有发生改变,说明此时没有steal和pop在和当前线程发生竞争,那么直接返回;如果top发生改变,说明发生了竞争,那么重新进入循环,这里cas成功时使用seq_cst是为了和steal,pop的cas配对。

 

这里讲下这几个seq_cst的作用,注意,c++标准中对seq_cst的作用只是在release和acquire语义之上保证了在所有线程间有一个相同的单独全序,而保证不了内存修改的立即全局可见;即memory fence不等于可见性,memory fence保证的是可见性的顺序。

 

竞争主要为多个steal和pop竞争,此时以三个线程为例,队列中数据为两个,假设top = 0,bottom = 2,可能出问题的情况只能是在全句序中,线程1对bottom的修改在线程2或3的cas之前,否则两个都会被成功steal,pop不成功。

此时情况为,线程1的bottom为1,线程2,3的t = 0,b = 2,此时无论如何pop都会返回成功,因为判断发现队列中有不止一个数据。此时假设线程2成功steal,那么线程3的cas会失败,再下一次循环的时候,将会看到单独全序中之前更新过的bottom值,导致steal失败。如果不使用seq_cst的话将保证不了单独的全序,也就可能看不到之前更新过的bottom,导致既被push,又被pop的错误情况。

类成员定义中,bottom只会被当前线程修改,而top会被多线程修改,因此对top做了cacheline对齐以防止false sharing。

参考:

wxj大佬的博客

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值