在java 世界中我们使用synchronized 关键字对需要做同步的代码进行上锁操作,来保证同一时刻只有一个线程可以对加锁代码段进行同步操作.synchronized机制实现依赖对应虚拟机的实现,在android中实现该功能的就是art的Monitor部分.
一java代码:
Object o=new Object();
public class Thread01 implements Runnable {
public void run() {
Log.d("TEST"," loop begin");
synchronized (o) {
for(int i=0;i<10;i++){
Log.d("TEST"," loop"+i);
}
}
二:将该代码对应oat文件反编译的情况
oatdump --oat-file=base.odex
1: void com.example.test.MainActivity$Thread01.run() (dex_method_idx=9442)
DEX CODE:
0x0000: 1a02 540e | const-string v2, "TEST" // string@3668
0x0002: 1a03 5d00 | const-string v3, " loop begin" // string@93
0x0004: 7120 9a21 3200 | invoke-static {v2, v3}, int android.util.Log.d(java.lang.String, java.lang.String) // method@8602
0x0007: 5462 ca09 | iget-object v2, v6, Lcom/example/test/MainActivity; com.example.test.MainActivity$Thread01.this$0 // field@2506
0x0009: 5423 cb09 | iget-object v3, v2, Ljava/lang/Object; com.example.test.MainActivity.o // field@2507
0x000b: 1d03 | monitor-enter v3
0x000c: 1201 | const/4 v1, #+0
0x000d: 1302 0a00 | const/16 v2, #+10
0x000f: 3421 0400 | if-lt v1, v2, +4
0x0011: 1e03 | monitor-exit v3
...
0x0036: 0d02 | move-exception v2
0x0037: 1e03 | monitor-exit v3//期间发生异常也会走到释放锁的地方
以上可以看到对应synchronized的虚拟机指令就是monitor-enter 和monitor-exit 。对应art/runtime/Monitor.cc 中的Monitor::MonitorEnter和Monitor::MonitorExit 函数实现。
Monitor 锁的功能实现依赖linux 的futex功能和原子操作的原理, Futex主要的作用有两点:支持一种粒度锁的睡眠与唤醒操作,其次是管理进程挂起时的等待队列。这里介绍一下本文用到的API函数
一:futex 定义在art\runtime\base\ mutex-inl.h中,封装了SYS_futex系统调用,在art中 futex又被封装在了art::Mutex类里.
static inline int futex(volatile int *uaddr, int op, int val, const struct timespec *timeout,
volatile int *uaddr2, int val3) {
return syscall(SYS_futex, uaddr, op, val, timeout, uaddr2, val3);
}
常用API:
1: FUTEX_WAKE 参数:唤醒val个在state_.Address指向的锁变量上挂起等待的线程。如下唤醒1个线程
futex(state_.Address(), FUTEX_WAKE, 1, nullptr, nullptr, 0);
2:FUTEX_WAIT参数:当state_.Address处的值和val值相等时,进入等待状态。对应线程将不再执行,必须唤醒后才能执行后面的操作.
futex(state_.Address(), FUTEX_WAIT, cur_state, nullptr, nullptr, 0)
3:FUTEX_CMP_REQUEUE参数:当sequence_.Address地址处的值和cur_sequence相等时,将sequence_.Address处挂起等待队列,转移到guard_.state_.Address(),的等待队列上。
futex(sequence_.Address(), FUTEX_CMP_REQUEUE, 0,
reinterpret_cast(std::numeric_limits::max()),
guard_.state_.Address(), cur_sequence)
二:原子操作类Atomic定义在art\runtime\ atomic.h中,该类封装了c++ 的标准Atomic类。
template
class PACKED(sizeof(T)) Atomic : public std::atomic {}
typedef Atomic AtomicInteger;
该部分有点复杂,我们这里使用到的是一个32位整型数,常用的api方法LoadRelaxed 方法,获取对应地址处的值。
T LoadRelaxed() const {
return this->load(std::memory_order_relaxed);
}
未完待续。。。