Android pthread mutex 实现分析
2012-05-27 21:07
405 查看
在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_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会检测当前的状态。
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
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置为-1
int 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 Mutex实现
否则,感觉属性的type和shared进行设置
normal 的情况
在recursive的情况下,需要使用mutex来包含counter,
unlock的情况
trylock
timeout
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 0x2000 enum { 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 为Privateint 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置为-1
int 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_T 4000 YPE_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为0xdead10cc int 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 pthread mutex 实现分析
- pthread包的mutex实现分析
- Android support v4 FragmentActivity实现分析
- chromium for android v34 2dCanvas硬件绘制实现分析
- Android消息处理机制源码分析(二):本地实现
- pthread_mutex_lock的实现!!
- Android 4.4 WebView实现分析
- [置顶] Android Retrofit 2实现原理分析
- Android开发 使用jni对字符串加解密实现分析
- Android之实现登陆页面分析
- Android系统的智能指针(轻量级指针、强指针和弱指针)的实现原理分析
- Android 的 Handler 机制实现原理分析
- Android 串口通信笔记2 调试工具分析 工具类实现分析、项目实现
- Android初级教程通过简要分析“土司”源码,来自实现定义土司理论探讨
- 分析Android App中内置换肤功能的实现方式
- 基于TcpDump和pcap文件分析的Android平台网络抓包程序设计与实现【随便】
- Android视图SurfaceView的实现原理分析
- 【PTHREAD】linux 多线程编程---Mutex实现Service线程和work线程
- Android 7.0 虚拟按键(NavigationBar)源码分析 之 点击事件的实现流程
- Android XListView实现原理讲解及分析