Butex
butex是bthread使用的类futex的32bit同步原语,可用于bthreads或者pthreads的同步,不可用于同步多进程。
源码地址:bthread/butex.h bthread/butex.cpp
Butex数据结构
如图,每个Butex内部包含一个32bit的用于同步的value和一个WaiterList。bthread进行同步操作时先判断Butex中的value是否和expect value相等,若是那么此bthread拿到了这个Butex,否则在栈上分配一个Waiter,加入WaiterList等待唤醒,并切换上下文到下一个bthread。当唤醒发生,从WaiterList中删除Waiter,并调度该bthread
wait & wakeup模型
butex提供两种基本操作,wait和wake,对外提供的api基于这两种基本操作衍生,例如butex_wake_all,bthread_wake_except等。这里对wait和wake这两个基本操作组成的模型做剖析。
model1
thread1 thread2
wait() value = new_value
wake()
在这种模型中,thread1的wait()在thread2的wake()之前发生,注意wait()和wake()存在memory_order中的sequenced-before关系,而value不参与,只是在使用wake的线程中保证value的设置先于wake()发生,所以又细分了两种情况,即wait()看到了value,或者没看到。
对前者来说,全局顺序是
- thread2 value = new_value
- thread1 wait()
- thread2 wake()
value = new_value先于wait()发生,wait()不会进入睡眠而是直接返回,后续的wake()无效果。
对后者来说,全局顺序是
- thread1 wait()
- thread2 value = new value
- thread2 wake()
这里wait()先于value = new value发生,thread1看到的是old_value进入睡眠,在stage3中被thread2的wake()唤醒
model2
thread1 thread2
value = new_value
wake()
wait()
这种模型中只有一种情况,wait()看到value的新值,从而直接return
Butex生命周期
Butex的生命周期通过资源池管理,也就是说Butex对象一经从资源池中获取就不会被销毁,这样设计最主要的原因是为了解决butex_wake()和butex_destroy()之间的竞态条件,不妨看下下面这个场景
|