Android(安卓)pthread mutex 实现分析
在Android ICS中,pthead库对应的路径为:
Android\bionic\libc\bionic\pthread.c
Android\bionic\libc\bionic\pthread-atfork.c
Android\bionic\libc\bionic\pthread-rwlocks.c
Android\bionic\libc\bionic\pthread-timers.c
Android\bionic\libc\bionic\pthread_internal.h
Android\bionic\libc\include\pthread.h
其中mutex在pthread.c中,相关的API有:
//pthread mutexattr 操作int pthread_mutexattr_init(pthread_mutexattr_t *attr);int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type);int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type);int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared);int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared);//pthread mutex 操作int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);int pthread_mutex_destroy(pthread_mutex_t *mutex);int pthread_mutex_lock(pthread_mutex_t *mutex);int pthread_mutex_unlock(pthread_mutex_t *mutex);int pthread_mutex_trylock(pthread_mutex_t *mutex);int pthread_mutex_timedlock(pthread_mutex_t *mutex, struct timespec* ts);
pthread_mutex_t对应一个结构体,包含一个int字段
typedef struct{ int volatile value;} pthread_mutex_t;
int字段分为5个部分,
/*
a mutex is implemented as a 32-bit integer holding the following fields
* * bits: name description
* 31-16 tid owner thread's kernel id (recursive and errorcheck only)
* 15-14 type mutex type
* 13 shared process-shared flag
* 12-2 counter counter of recursive mutexes
* 1-0 state lock state (0, 1 or 2)
*/
定义了一些macro来获得各个部分,其中mutex的type分为3类,有Normal, Recursive, Errorcheck,Recursize允许递归,Errorcheck会检测当前的状态。
#define MUTEX_OWNER(m) (((m)->value >> 16) & 0xffff)#define MUTEX_COUNTER(m) (((m)->value >> 2) & 0xfff)#define MUTEX_TYPE_MASK 0xc000#define MUTEX_TYPE_NORMAL 0x0000#define MUTEX_TYPE_RECURSIVE 0x4000#define MUTEX_TYPE_ERRORCHECK 0x8000#define MUTEX_COUNTER_SHIFT 2#define MUTEX_COUNTER_MASK 0x1ffc#define MUTEX_SHARED_MASK 0x2000enum { PTHREAD_MUTEX_NORMAL = 0, PTHREAD_MUTEX_RECURSIVE = 1, PTHREAD_MUTEX_ERRORCHECK = 2, PTHREAD_MUTEX_ERRORCHECK_NP = PTHREAD_MUTEX_ERRORCHECK, PTHREAD_MUTEX_RECURSIVE_NP = PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL};
1 Mutex属性
pthread_mutexattr_t用来描述mutex的属性,
typedef long pthread_mutexattr_t;
属性包含了mutex的type,以及sharedflag。对应于mutex_t
* 15-14 type mutex type
* 13 shared process-shared flag
/* a mutex attribute holds the following fields
*
* bits: name description
* 0-3 type type of mutex
* 4 shared process-shared flag
*/
#define MUTEXATTR_TYPE_MASK 0x000f
#define MUTEXATTR_SHARED_MASK 0x0010
#define PTHREAD_PROCESS_PRIVATE 0
#define PTHREAD_PROCESS_SHARED 1
1.1 init和destory
init将type设置为Default,也就是Normal(0)也就是,type=Normal, shared 为Private
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr){ int value = 0; if (mutex == NULL) return EINVAL; if (__likely(attr == NULL)) { mutex->value = MUTEX_TYPE_NORMAL; return 0; } if ((*attr & MUTEXATTR_SHARED_MASK) != 0) value |= MUTEX_SHARED_MASK; switch (*attr & MUTEXATTR_TYPE_MASK) { case PTHREAD_MUTEX_NORMAL: value |= MUTEX_TYPE_NORMAL; break; case PTHREAD_MUTEX_RECURSIVE: value |= MUTEX_TYPE_RECURSIVE; break; case PTHREAD_MUTEX_ERRORCHECK: value |= MUTEX_TYPE_ERRORCHECK; break; default: return EINVAL; } mutex->value = value; return 0;}//destory将attr置为-1int pthread_mutex_destroy(pthread_mutex_t *mutex){ int ret; /* use trylock to ensure that the mutex value is * valid and is not already locked. */ ret = pthread_mutex_trylock(mutex); if (ret != 0) return ret; mutex->value = 0xdead10cc; return 0;}
1.2 settype 和gettype
对pthread_mutexattr_t的type字段进行取值和赋值
int pthread_mutexattr_gettype(const pthread_mutexattr_t *attr, int *type){ if (attr) { int atype = (*attr & MUTEXATTR_TYPE_MASK); if (atype >= PTHREAD_MUTEX_NORMAL && atype <= PTHREAD_MUTEX_ERRORCHECK) { *type = atype; return 0; } } return EINVAL;}int pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type){ if (attr && type >= PTHREAD_MUTEX_NORMAL && type <= PTHREAD_MUTEX_ERRORCHECK ) { *attr = (*attr & ~MUTEXATTR_TYPE_MASK) | type; return 0; } return EINVAL;}
1.3 setpshared和getpshared
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr, int pshared){ if (!attr) return EINVAL; switch (pshared) { case PTHREAD_PROCESS_PRIVATE: *attr &= ~MUTEXATTR_SHARED_MASK; return 0; case PTHREAD_PROCESS_SHARED: /* our current implementation of pthread actually supports shared * mutexes but won't cleanup if a process dies with the mutex held. * Nevertheless, it's better than nothing. Shared mutexes are used * by surfaceflinger and audioflinger. */ *attr |= MUTEXATTR_SHARED_MASK; return 0; } return EINVAL;}int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr, int *pshared){ if (!attr || !pshared) return EINVAL; *pshared = (*attr & MUTEXATTR_SHARED_MASK) ? PTHREAD_PROCESS_SHARED : PTHREAD_PROCESS_PRIVATE; return 0;}
2 Mutex实现
2.1 Mutex init和 destory
如果attr==NULL,则采用默认属性, type =normal, shared = private,
否则,感觉属性的type和shared进行设置
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr){ int value = 0; if (mutex == NULL) return EINVAL; if (__likely(attr == NULL)) { mutex->value = MUTEX_TYPE_NORMAL; return 0; } if ((*attr & MUTEXATTR_SHARED_MASK) != 0) value |= MUTEX_SHARED_MASK; switch (*attr & MUTEXATTR_TYPE_MASK) { case PTHREAD_MUTEX_NORMAL: value |= MUTEX_TYPE_NORMAL; break; case PTHREAD_MUTEX_RECURSIVE: value |= MUTEX_TYPE_RECURSIVE; break; case PTHREAD_MUTEX_ERRORCHECK: value |= MUTEX_TYPE_ERRORCHECK; break; default: return EINVAL; } mutex->value = value; return 0;}如果mutex当前不被lock,则设置value为0xdead10ccint pthread_mutex_destroy(pthread_mutex_t *mutex){ int ret; /* use trylock to ensure that the mutex value is * valid and is not already locked. */ ret = pthread_mutex_trylock(mutex); if (ret != 0) return ret; mutex->value = 0xdead10cc; return 0;}
2.2 lock, unlock, trylock, timedlock
int pthread_mutex_lock(pthread_mutex_t *mutex){ int mtype, tid, new_lock_type, shared; if (__unlikely(mutex == NULL)) return EINVAL; mtype = (mutex->value & MUTEX_TYPE_MASK); shared = (mutex->value & MUTEX_SHARED_MASK); /* Handle normal case first */ if ( __likely(mtype == MUTEX_TYPE_NORMAL) ) {//type为normal, _normal_lock(mutex); return 0; } /* Do we already own this recursive or error-check mutex ? */ tid = __get_thread()->kernel_id; if ( tid == MUTEX_OWNER(mutex) )//已经持有mutex,递归的情况 { int oldv, counter; if (mtype == MUTEX_TYPE_ERRORCHECK) { /* trying to re-lock a mutex we already acquired */ return EDEADLK; } /* * We own the mutex, but other threads are able to change * the contents (e.g. promoting it to "contended"), so we * need to hold the global lock. */ _recursive_lock();//更新counter oldv = mutex->value; counter = (oldv + (1 << MUTEX_COUNTER_SHIFT)) & MUTEX_COUNTER_MASK; mutex->value = (oldv & ~MUTEX_COUNTER_MASK) | counter; _recursive_unlock(); return 0; } /* We don't own the mutex, so try to get it. * * First, we try to change its state from 0 to 1, if this * doesn't work, try to change it to state 2. */ new_lock_type = 1; /* compute futex wait opcode and restore shared flag in mtype */ mtype |= shared; for (;;) { int oldv; _recursive_lock(); oldv = mutex->value; if (oldv == mtype) { /* uncontended released lock => 1 or 2 */ mutex->value = ((tid << 16) | mtype | new_lock_type); } else if ((oldv & 3) == 1) { /* locked state 1 => state 2 */ oldv ^= 3; mutex->value = oldv; } _recursive_unlock(); if (oldv == mtype) break; /* * The lock was held, possibly contended by others. From * now on, if we manage to acquire the lock, we have to * assume that others are still contending for it so that * we'll wake them when we unlock it. */ new_lock_type = 2; __futex_wait_ex(&mutex->value, shared, oldv, NULL); } return 0;}
normal 的情况
/* * Lock a non-recursive mutex. * * As noted above, there are three states: * 0 (unlocked, no contention) * 1 (locked, no contention) * 2 (locked, contention) * * Non-recursive mutexes don't use the thread-id or counter fields, and the * "type" value is zero, so the only bits that will be set are the ones in * the lock state field. */static __inline__ void_normal_lock(pthread_mutex_t* mutex){ /* We need to preserve the shared flag during operations */ int shared = mutex->value & MUTEX_SHARED_MASK; /* * The common case is an unlocked mutex, so we begin by trying to * change the lock's state from 0 to 1. __atomic_cmpxchg() returns 0 * if it made the swap successfully. If the result is nonzero, this * lock is already held by another thread. */ if (__atomic_cmpxchg(shared|0, shared|1, &mutex->value ) != 0) { /* * We want to go to sleep until the mutex is available, which * requires promoting it to state 2. We need to swap in the new * state value and then wait until somebody wakes us up. * * __atomic_swap() returns the previous value. We swap 2 in and * see if we got zero back; if so, we have acquired the lock. If * not, another thread still holds the lock and we wait again. * * The second argument to the __futex_wait() call is compared * against the current value. If it doesn't match, __futex_wait() * returns immediately (otherwise, it sleeps for a time specified * by the third argument; 0 means sleep forever). This ensures * that the mutex is in state 2 when we go to sleep on it, which * guarantees a wake-up call. */ while (__atomic_swap(shared|2, &mutex->value ) != (shared|0))//等待muex __futex_wait_ex(&mutex->value, shared, shared|2, 0); } ANDROID_MEMBAR_FULL();}
在recursive的情况下,需要使用mutex来包含counter,
static pthread_mutex_t __recursive_lock = PTHREAD_MUTEX_INITIALIZER;static void_recursive_lock(void){ _normal_lock(&__recursive_lock);}static void_recursive_unlock(void){ _normal_unlock(&__recursive_lock );}
unlock的情况
int pthread_mutex_unlock(pthread_mutex_t *mutex){ int mtype, tid, oldv, shared; if (__unlikely(mutex == NULL)) return EINVAL; mtype = (mutex->value & MUTEX_TYPE_MASK); shared = (mutex->value & MUTEX_SHARED_MASK); /* Handle common case first */ if (__likely(mtype == MUTEX_TYPE_NORMAL)) {//normal _normal_unlock(mutex); return 0; } /* Do we already own this recursive or error-check mutex ? */ tid = __get_thread()->kernel_id; if ( tid != MUTEX_OWNER(mutex) )//error check的情况,错误退出 return EPERM; /* We do, decrement counter or release the mutex if it is 0 */ _recursive_lock(); oldv = mutex->value; if (oldv & MUTEX_COUNTER_MASK) { mutex->value = oldv - (1 << MUTEX_COUNTER_SHIFT); oldv = 0; } else { mutex->value = shared | mtype; } _recursive_unlock(); /* Wake one waiting thread, if any */ if ((oldv & 3) == 2) { __futex_wake_ex(&mutex->value, shared, 1); } return 0;}/* * Release a non-recursive mutex. The caller is responsible for determining * that we are in fact the owner of this lock. */static __inline__ void_normal_unlock(pthread_mutex_t* mutex){ ANDROID_MEMBAR_FULL(); /* We need to preserve the shared flag during operations */ int shared = mutex->value & MUTEX_SHARED_MASK; /* * The mutex state will be 1 or (rarely) 2. We use an atomic decrement * to release the lock. __atomic_dec() returns the previous value; * if it wasn't 1 we have to do some additional work. */ if (__atomic_dec(&mutex->value) != (shared|1)) { /* * Start by releasing the lock. The decrement changed it from * "contended lock" to "uncontended lock", which means we still * hold it, and anybody who tries to sneak in will push it back * to state 2. * * Once we set it to zero the lock is up for grabs. We follow * this with a __futex_wake() to ensure that one of the waiting * threads has a chance to grab it. * * This doesn't cause a race with the swap/wait pair in * _normal_lock(), because the __futex_wait() call there will * return immediately if the mutex value isn't 2. */ mutex->value = shared; /* * Wake up one waiting thread. We don't know which thread will be * woken or when it'll start executing -- futexes make no guarantees * here. There may not even be a thread waiting. * * The newly-woken thread will replace the 0 we just set above * with 2, which means that when it eventually releases the mutex * it will also call FUTEX_WAKE. This results in one extra wake * call whenever a lock is contended, but lets us avoid forgetting * anyone without requiring us to track the number of sleepers. * * It's possible for another thread to sneak in and grab the lock * between the zero assignment above and the wake call below. If * the new thread is "slow" and holds the lock for a while, we'll * wake up a sleeper, which will swap in a 2 and then go back to * sleep since the lock is still held. If the new thread is "fast", * running to completion before we call wake, the thread we * eventually wake will find an unlocked mutex and will execute. * Either way we have correct behavior and nobody is orphaned on * the wait queue. */ __futex_wake_ex(&mutex->value, shared, 1);//唤醒等待的 }}
trylock
int pthread_mutex_trylock(pthread_mutex_t *mutex){ int mtype, tid, oldv, shared; if (__unlikely(mutex == NULL)) return EINVAL; mtype = (mutex->value & MUTEX_TYPE_MASK); shared = (mutex->value & MUTEX_SHARED_MASK); /* Handle common case first */ if ( __likely(mtype == MUTEX_TYPE_NORMAL) ) { if (__atomic_cmpxchg(shared|0, shared|1, &mutex->value) == 0) { ANDROID_MEMBAR_FULL(); return 0; } return EBUSY; } /* Do we already own this recursive or error-check mutex ? */ tid = __get_thread()->kernel_id; if ( tid == MUTEX_OWNER(mutex) )//当前thread已经持有mutex { int counter; if (mtype == MUTEX_TYPE_ERRORCHECK) { /* already locked by ourselves */ return EDEADLK; } //更新counter计数器 _recursive_lock(); oldv = mutex->value; counter = (oldv + (1 << MUTEX_COUNTER_SHIFT)) & MUTEX_COUNTER_MASK; mutex->value = (oldv & ~MUTEX_COUNTER_MASK) | counter; _recursive_unlock(); return 0; } /* Restore sharing bit in mtype */ mtype |= shared; /* Try to lock it, just once. */ _recursive_lock(); oldv = mutex->value; if (oldv == mtype) /* uncontended released lock => state 1 */ mutex->value = ((tid << 16) | mtype | 1); _recursive_unlock(); if (oldv != mtype) return EBUSY; return 0;}
timeout
int pthread_mutex_lock_timeout_np(pthread_mutex_t *mutex, unsigned msecs){ clockid_t clock = CLOCK_MONOTONIC; struct timespec abstime; struct timespec ts; int mtype, tid, oldv, new_lock_type, shared; /* compute absolute expiration time */ __timespec_to_relative_msec(&abstime, msecs, clock); if (__unlikely(mutex == NULL)) return EINVAL; mtype = (mutex->value & MUTEX_TYPE_MASK); shared = (mutex->value & MUTEX_SHARED_MASK); /* Handle common case first */ if ( __likely(mtype == MUTEX_TYPE_NORMAL) )//normal的情况 { /* fast path for uncontended lock */ if (__atomic_cmpxchg(shared|0, shared|1, &mutex->value) == 0) { ANDROID_MEMBAR_FULL(); return 0; } //在while循环中等待,直到超时或者获得mutex /* loop while needed */ while (__atomic_swap(shared|2, &mutex->value) != (shared|0)) { if (__timespec_to_absolute(&ts, &abstime, clock) < 0) return EBUSY; __futex_wait_ex(&mutex->value, shared, shared|2, &ts); } ANDROID_MEMBAR_FULL(); return 0; } /* Do we already own this recursive or error-check mutex ? */ tid = __get_thread()->kernel_id; if ( tid == MUTEX_OWNER(mutex) ) { int oldv, counter; if (mtype == MUTEX_TYPE_ERRORCHECK) { /* already locked by ourselves */ return EDEADLK; } _recursive_lock(); oldv = mutex->value; counter = (oldv + (1 << MUTEX_COUNTER_SHIFT)) & MUTEX_COUNTER_MASK; mutex->value = (oldv & ~MUTEX_COUNTER_MASK) | counter; _recursive_unlock(); return 0; } /* We don't own the mutex, so try to get it. * * First, we try to change its state from 0 to 1, if this * doesn't work, try to change it to state 2. */ new_lock_type = 1; /* Compute wait op and restore sharing bit in mtype */ mtype |= shared; //循环等待,直到超时 for (;;) { int oldv; struct timespec ts; _recursive_lock(); oldv = mutex->value; if (oldv == mtype) { /* uncontended released lock => 1 or 2 */ mutex->value = ((tid << 16) | mtype | new_lock_type); } else if ((oldv & 3) == 1) { /* locked state 1 => state 2 */ oldv ^= 3; mutex->value = oldv; } _recursive_unlock(); if (oldv == mtype) break; /* * The lock was held, possibly contended by others. From * now on, if we manage to acquire the lock, we have to * assume that others are still contending for it so that * we'll wake them when we unlock it. */ new_lock_type = 2; //超时退出 if (__timespec_to_absolute(&ts, &abstime, clock) < 0) return EBUSY; __futex_wait_ex(&mutex->value, shared, oldv, &ts); } return 0;}
更多相关文章
- Android中visibility属性VISIBLE、INVISIBLE、GONE的区别
- Android如何在xml布局中使用自定义属性
- Android之补间动画和属性动画
- android 自定义view之(一) Creating a View Class
- android ViewFlipper
- Android中TextView所带的各类属性的使用
- android 笔记 --- 自定义Android主题风格theme.xml方法
- Android(安卓)EditView属性详细介绍
- Android中Touch事件的处理