thread in android ndk

android 高版本加入了c++2.0,和2.0+的標準庫的一些東西,例如:std::thread,當然低版本使用還是Thread,不過他們都封裝了pthread。

我在9.0的Thread源碼中發現瞭如下一段話:

39// DO NOT USE: please use std::thread
40
41class Thread : virtual public RefBase
42{。。。。。。

可能是引入了c++2.0 or above的標準庫的緣由,也可能是Thread.cpp/Mutex.cpp等的功能不如std::來的齊全,所以不推薦使用Thread類,推薦使用std::thread類,說法不正確的話,看到的朋友可以在評論區指出下。

std::相關

android使用的實現庫是llvm的libc++庫,thread是一個class,看一下構造函數:

//std::thread  in thread [no suffix] file
290	thread::thread(_Fp&& __f, _Args&&... __args)
291	{
292	    typedef unique_ptr<__thread_struct> _TSPtr;
293	    _TSPtr __tsp(new __thread_struct);
294	    typedef tuple<_TSPtr, typename decay<_Fp>::type, typename decay<_Args>::type...> _Gp;
295	    _VSTD::unique_ptr<_Gp> __p(
296	            new _Gp(std::move(__tsp),
297	                    __decay_copy(_VSTD::forward<_Fp>(__f)),
298	                    __decay_copy(_VSTD::forward<_Args>(__args))...));
299	    int __ec = __libcpp_thread_create(&__t_, &__thread_proxy<_Gp>, __p.get());
300	    if (__ec == 0)
301	        __p.release();
302	    else
303	        __throw_system_error(__ec, "thread constructor failed");
304	}


276	template <class _Fp>
277	void* __thread_proxy(void* __vp)
278	{
279	    // _Fp = std::tuple< unique_ptr<__thread_struct>, Functor, Args...>
280	    std::unique_ptr<_Fp> __p(static_cast<_Fp*>(__vp));
281	    __thread_local_data().set_pointer(_VSTD::get<0>(*__p).release());
282	    typedef typename __make_tuple_indices<tuple_size<_Fp>::value, 2>::type _Index;
283	    __thread_execute(*__p, _Index());
284	    return nullptr;
285	}

//__threading_support[no suffix]
333	int __libcpp_thread_create(__libcpp_thread_t *__t, void *(*__func)(void *),
334	                           void *__arg)
335	{
336	  return pthread_create(__t, 0, __func, __arg);
337	}

最終調用到了pthread的pthread_create方法。

//std::mutex [mutex.cpp]
30	void
31	mutex::lock()
32	{
33	    int ec = __libcpp_mutex_lock(&__m_);//!!!
34	    if (ec)
35	        __throw_system_error(ec, "mutex lock failed");
36	}

44	void
45	mutex::unlock() _NOEXCEPT
46	{
47	    int ec = __libcpp_mutex_unlock(&__m_);//!!!
48	    (void)ec;
49	    _LIBCPP_ASSERT(ec == 0, "call to mutex::unlock failed");
50	}

//mutex_destructor.cpp
31	class _LIBCPP_TYPE_VIS mutex
32	{
33	    __libcpp_mutex_t __m_ = _LIBCPP_MUTEX_INITIALIZER;//!!!
34	
35	public:
36	    _LIBCPP_ALWAYS_INLINE _LIBCPP_INLINE_VISIBILITY
37	    constexpr mutex() = default;
38	    mutex(const mutex&) = delete;
39	    mutex& operator=(const mutex&) = delete;
40	    ~mutex() noexcept;
41	};
42	
43	
44	mutex::~mutex() _NOEXCEPT
45	{
46	    __libcpp_mutex_destroy(&__m_);//!!!
47	}

//__threading_support [no suffix]
57	typedef pthread_mutex_t __libcpp_mutex_t;//!!!

262	int __libcpp_mutex_lock(__libcpp_mutex_t *__m)
263	{
264	  return pthread_mutex_lock(__m);//!!!
265	}

272	int __libcpp_mutex_unlock(__libcpp_mutex_t *__m)
273	{
274	  return pthread_mutex_unlock(__m);//!!!
275	}

277	int __libcpp_mutex_destroy(__libcpp_mutex_t *__m)
278	{
279	  return pthread_mutex_destroy(__m);//!!!
280	}

///bionic/libc/include/pthread.h
41enum {
42  PTHREAD_MUTEX_NORMAL = 0,
43  PTHREAD_MUTEX_RECURSIVE = 1,
44  PTHREAD_MUTEX_ERRORCHECK = 2,
45
46  PTHREAD_MUTEX_ERRORCHECK_NP = PTHREAD_MUTEX_ERRORCHECK,
47  PTHREAD_MUTEX_RECURSIVE_NP  = PTHREAD_MUTEX_RECURSIVE,
48
49  PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
50};

52#define PTHREAD_MUTEX_INITIALIZER { { ((PTHREAD_MUTEX_NORMAL & 3) << 14) } }

std::mutex的lock(),unlock(),~mutex()也是通過_libcpp中轉到了pthread_mutex_lock,pthread_mutex_unlock,pthread_mutex_destroy,讓pthread承擔起來。

其他的互斥體也是如此,不一一羅列。

 Thread相關

 /system/core/libutils/Threads.cpp

使用Thread,sp<Thread> t = new Thread(false); t.run("threadname",PRIORITY_NORMAL);最終會調用到pthread的pthread_create方法。

/system/core/libutils/include/utils/Mutex.h

162inline Mutex::Mutex() {
163    pthread_mutex_init(&mMutex, NULL);
164}
165inline Mutex::Mutex(__attribute__((unused)) const char* name) {
166    pthread_mutex_init(&mMutex, NULL);
167}
168inline Mutex::Mutex(int type, __attribute__((unused)) const char* name) {
169    if (type == SHARED) {
170        pthread_mutexattr_t attr;
171        pthread_mutexattr_init(&attr);
172        pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
173        pthread_mutex_init(&mMutex, &attr);
174        pthread_mutexattr_destroy(&attr);
175    } else {
176        pthread_mutex_init(&mMutex, NULL);
177    }
178}
179inline Mutex::~Mutex() {
180    pthread_mutex_destroy(&mMutex);
181}
182inline status_t Mutex::lock() {
183    return -pthread_mutex_lock(&mMutex);
184}
185inline void Mutex::unlock() {
186    pthread_mutex_unlock(&mMutex);
187}
188inline status_t Mutex::tryLock() {
189    return -pthread_mutex_trylock(&mMutex);
190}
191#if defined(__ANDROID__)
192inline status_t Mutex::timedLock(nsecs_t timeoutNs) {
193    timeoutNs += systemTime(SYSTEM_TIME_REALTIME);
194    const struct timespec ts = {
195        /* .tv_sec = */ static_cast<time_t>(timeoutNs / 1000000000),
196        /* .tv_nsec = */ static_cast<long>(timeoutNs % 1000000000),
197    };
198    return -pthread_mutex_timedlock(&mMutex, &ts);
199}
200#endif

Mutex也是使用到了pthread。

std::和Thread這兩項,都用到了pthread,可見pthread在android中的重要性。java中LockSupport的native使用的也是pthread.

其實pthread是我的叫法,它的正確叫法是Pthreads,POSIX Threads,是POSIX線程標準,定義了創建和操縱線程的一套API

標準就是指API,它是跨平臺(os)的接口,android可能借用linux的Pthreads庫,實現了這套標準。看來制定標準的都在想着要做老大。

pthread lock and unlock

鎖類型有三種:1.MUTEX_TYPE_BITS_NORMAL普通鎖,非其餘兩種,2.MUTEX_TYPE_BITS_RECURSIVE支持重入,3. MUTEX_TYPE_BITS_ERRORCHECK,支持錯誤檢查。我們只看普通鎖。

798int pthread_mutex_lock(pthread_mutex_t* mutex_interface) {
......
807
808    pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
//原子load到state的字段值
809    uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
810    uint16_t mtype = (old_state & MUTEX_TYPE_MASK);
       //避免減慢獲取正常互斥鎖的快速路徑,TryLock一次
811    // Avoid slowing down fast path of normal mutex lock operation.
812    if (__predict_true(mtype == MUTEX_TYPE_BITS_NORMAL)) {
813        uint16_t shared = (old_state & MUTEX_SHARED_MASK);
//
814        if (__predict_true(NonPI::NormalMutexTryLock(mutex, shared) == 0)) {
815            return 0;
816        }
817    }
......
        //沒有獲取到,state的1-0位非0
829    return NonPI::MutexLockWithTimeout(mutex, false, nullptr);
830}

其中pthread_mutex_internal_t有2種機器下的定義:一種是指針位是64位,還有一種是32位的,我只看32位的:

471struct pthread_mutex_internal_t {
472    _Atomic(uint16_t) state;
473    union {
474        _Atomic(uint16_t) owner_tid;
475        uint16_t pi_mutex_id;
476    };
477
478    PIMutex& ToPIMutex() {
479        return PIMutexAllocator::IdToPIMutex(pi_mutex_id);
480    }
481
482    void FreePIMutex() {
483        PIMutexAllocator::FreeId(pi_mutex_id);
484    }
485} __attribute__((aligned(4)));

可以看到pthread_mutex_internal_t 類型的變量在內存中的排放是: _Atomic(uint16_t) state + union.

//對於32位互斥鎖,它包括以下字段:
435//   Atomic(uint16_t) state;
436//   atomic_int owner_tid;  // 32位程序中的Atomic(uint16_t)
437//
438//   state包含以下字段:
439//
440//   bits:     name     description
441//   15-14     type     mutex type, can be 0 (normal), 1 (recursive), 2 (errorcheck)
442//   13        shared   process-shared flag
443//   12-2      counter  <number of times a thread holding a recursive Non-PI mutex> - 1
444//   1-0       state    lock state (0, 1 or 2)
445//
446//   bits 15-13 are constant during the lifetime of the mutex.
   //   15-13位在互斥對象的生存期內是不變的。
447//
448//   owner_tid is used only in recursive and errorcheck Non-PI mutexes to hold the mutex owner thread id.
//owner_tid僅用於遞歸和錯誤檢查以保持互斥鎖所有者

16位原子變量state的1-0位的值,0表示未鎖定,1表示有一個線程取走了鎖,2表示有1+個線程在等待獲取鎖。接下來在lock和unlock的時候,我們關注16位原子變量state的1-0兩位的變換,以及致使其變化的一些原子操作。

先看trylock:

554static inline __always_inline int NormalMutexTryLock(pthread_mutex_internal_t* mutex,
555                                                     uint16_t shared) {
//16位unlocked的1-0爲0
556    const uint16_t unlocked           = shared | MUTEX_STATE_BITS_UNLOCKED;
//16位locked_uncontended的1-0爲1
557    const uint16_t locked_uncontended = shared | MUTEX_STATE_BITS_LOCKED_UNCONTENDED;
558
559    uint16_t old_state = unlocked;
//比較&mutex->state和&old_state並交換locked_uncontended到&mutex->state,成功的話state字段1-0爲1,示爲有一個線程獲取了鎖。
560    if (__predict_true(atomic_compare_exchange_strong_explicit(&mutex->state, &old_state,
561                         locked_uncontended, memory_order_acquire, memory_order_relaxed))) {
562        return 0;
563    }
564    return EBUSY;
565}

假定trylock失敗了,可能的失敗是:已經有1個線程獲取了鎖(1-0位爲1),或者1+個線程在等待(1-0位爲1).失敗就走至NonPI::MutexLockWithTimeout(mutex, false, nullptr)。

701static int MutexLockWithTimeout(pthread_mutex_internal_t* mutex, bool use_realtime_clock,
702                                const timespec* abs_timeout_or_null) {
703    uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
704    uint16_t mtype = (old_state & MUTEX_TYPE_MASK);
705    uint16_t shared = (old_state & MUTEX_SHARED_MASK);
706
707    // Handle common case first.
708    if ( __predict_true(mtype == MUTEX_TYPE_BITS_NORMAL) ) {
709        return NormalMutexLock(mutex, shared, use_realtime_clock, abs_timeout_or_null);
710    }
......
782}


579static inline __always_inline int NormalMutexLock(pthread_mutex_internal_t* mutex,
580                                                  uint16_t shared,
581                                                  bool use_realtime_clock,
582                                                  const timespec* abs_timeout_or_null) {
583    if (__predict_true(NormalMutexTryLock(mutex, shared) == 0)) {
584        return 0;
585    }
586    int result = check_timespec(abs_timeout_or_null, true);
587    if (result != 0) {
588        return result;
589    }
590
591    ScopedTrace trace("Contending for pthread mutex");
//16位unlocked的1-0爲0
593    const uint16_t unlocked           = shared | MUTEX_STATE_BITS_UNLOCKED;
//16位locked_contended 的1-0爲2
594    const uint16_t locked_contended = shared | MUTEX_STATE_BITS_LOCKED_CONTENDED;
......
//原子交換&mutex->state和locked_contended的值,如果&mutex->state舊值的1-0位不是0(未鎖定),說明有至少一個線程獲取了鎖。
604    while (atomic_exchange_explicit(&mutex->state, locked_contended,
605                                    memory_order_acquire) != unlocked) {
//只允許一個線程獲取鎖,其他線程在此被內核加入了進程等待隊列,等待被喚醒。
606        if (__futex_wait_ex(&mutex->state, shared, locked_contended, use_realtime_clock,
607                            abs_timeout_or_null) == -ETIMEDOUT) {
608            return ETIMEDOUT;
609        }
610    }
611    return 0;
612}

看一下unlock:

832int pthread_mutex_unlock(pthread_mutex_t* mutex_interface) {
。。。。。。
841
842    pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);
843    uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);
844    uint16_t mtype  = (old_state & MUTEX_TYPE_MASK);
845    uint16_t shared = (old_state & MUTEX_SHARED_MASK);
846
847    // Handle common case first.
848    if (__predict_true(mtype == MUTEX_TYPE_BITS_NORMAL)) {
849        NonPI::NormalMutexUnlock(mutex, shared);
850        return 0;
851    }
。。。。。。
887    return 0;
888}


618static inline __always_inline void NormalMutexUnlock(pthread_mutex_internal_t* mutex,
619                                                     uint16_t shared) {
620    const uint16_t unlocked         = shared | MUTEX_STATE_BITS_UNLOCKED;
621    const uint16_t locked_contended = shared | MUTEX_STATE_BITS_LOCKED_CONTENDED;
。。。。。。
//原子交換&mutex->state和unlocked的值,如果&mutex->state舊值的1-0位是2(未鎖定),說明有至少一個線程在等待獲取鎖。
628    if (atomic_exchange_explicit(&mutex->state, unlocked,
629                                 memory_order_release) == locked_contended) {
。。。。。。
//好,既然有等待的線程,那麼我們就喚醒在&mutex->state等待的線程,可能是非公平鎖,喚醒所有線程去競爭。
648        __futex_wake_ex(&mutex->state, shared, 1);
649    }
650}

總結一下lock和unlock:

//lock
void lock(pthread_mutex_internal_t* mutex) {
//trylock is successed
    uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed)
    const uint16_t unlocked         = old_state | MUTEX_STATE_BITS_UNLOCKED;
    old_state = unlocked;
    if (__predict_true(atomic_compare_exchange_strong_explicit(&mutex->state, &old_state, locked_uncontended, memory_order_acquire, memory_order_relaxed))) {
        return 0;
    }
//trylock is failed
    uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed)
    const uint16_t unlocked         = old_state | MUTEX_STATE_BITS_UNLOCKED;
    const uint16_t locked_contended = old_state | MUTEX_STATE_BITS_LOCKED_CONTENDED;
//喚醒後的線程繼續在此原子修改&mutex->state爲locked_contended,先修改的線程不用再等待(unlock時修改爲unlocked了)先進入臨界區,後修改的返回值一直爲locked_contended(!=unlocked),所以繼續等待
    while (atomic_exchange_explicit(&mutex->state, locked_contended, memory_order_acquire) != unlocked) {
        if (__futex_wait_ex(&mutex->state, shared, locked_contended, use_realtime_clock, abs_timeout_or_null) == -ETIMEDOUT) {
            return ETIMEDOUT;
        }
    }
}

//unlock
void unlock(pthread_mutex_internal_t* mutex) {
       uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed)
       const uint16_t unlocked         = old_state | MUTEX_STATE_BITS_UNLOCKED;
       const uint16_t locked_contended = old_state | MUTEX_STATE_BITS_LOCKED_CONTENDED;
//把&mutex->state重新置換爲未鎖定狀態,有線程等待的話就喚醒在&mutex->state上等待的線程,喚醒後幹甚就取看看lock裏幹了什麼
       if (atomic_exchange_explicit(&mutex->state, unlocked,memory_order_release) == locked_contended) {
           __futex_wake_ex(&mutex->state, shared, 1);
       }
}

但是我覺着把上面的atomic_compare_exchange_strong_explicit和atomic_exchange_explicit的memory_order換成memory_order_relaxed也是沒有問題的。不知道此推斷對不對,看到的可以討論下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章