在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;}






 

更多相关文章

  1. Android中visibility属性VISIBLE、INVISIBLE、GONE的区别
  2. Android如何在xml布局中使用自定义属性
  3. Android之补间动画和属性动画
  4. android 自定义view之(一) Creating a View Class
  5. android ViewFlipper
  6. Android中TextView所带的各类属性的使用
  7. android 笔记 --- 自定义Android主题风格theme.xml方法
  8. Android(安卓)EditView属性详细介绍
  9. Android中Touch事件的处理

随机推荐

  1. maven 插件用于打不同环境的版本包
  2. JavaScript中的数据类型转换
  3. 0基础学习Python该如何入门?Python学习方
  4. [翻译]微服务设计模式 - 8. 服务发现 -
  5. 如何在苹果Mac上的“邮件”中导入或导出
  6. [翻译]微服务设计模式 - 7. 服务发现 -
  7. nginx负载均衡简单设置
  8. Linux下典型IO模型 +select多路转接模型(
  9. JS数组性能小则|你以为的快不是真的快
  10. 曝苹果新款iPad Pro最早4月推出:配备雷电