在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" // [email protected]
      0x0002: 1a03 5d00                 | const-string v3, " loop begin" // [email protected]
      0x0004: 7120 9a21 3200            | invoke-static {v2, v3}, int android.util.Log.d(java.lang.String, java.lang.String) // [email protected]
      0x0007: 5462 ca09                 | iget-object v2, v6, Lcom/example/test/MainActivity; com.example.test.MainActivity$Thread01.this$0 // [email protected]
      0x0009: 5423 cb09                 | iget-object v3, v2, Ljava/lang/Object; com.example.test.MainActivity.o // [email protected]
      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<const timespec*>(std::numeric_limits<int32_t>::max()),

                   guard_.state_.Address(), cur_sequence)

二:原子操作類Atomic定義在art\runtime\ atomic.h中,該類封裝了c++ 的標準Atomic類。

template<typename T>

class PACKED(sizeof(T)) Atomic : public std::atomic<T> {}

typedef Atomic<int32_t> AtomicInteger;

該部分有點複雜,我們這裡使用到的是一個32位整型數,常用的api方法LoadRelaxed 方法,獲取對應地址處的值。

  T LoadRelaxed() const {

    return this->load(std::memory_order_relaxed);

  }

未完待續。。。

.