art中的monitor机制--java 中 Synchronized与art Monitor的关系

在java 世界中我们使用synchronized 关键字对需要做同步的代码进行上锁操作,来保证同一时刻只有一个线程可以对加锁代码段进行同步操作.synchronized机制实现依赖对应虚拟机的实现,在android中实现该功能的就是art的Monitor部分.

1 实验:

一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 函数实现。

2 预备知识

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);

  }

未完待续。。。

你可能感兴趣的:(art)