android mutex 详细介绍
来源:互联网 发布:sor文件打开软件 编辑:程序博客网 时间:2024/06/02 00:59
一个进程中不可能只有一个线程在战斗,所以一个进程中一般都是有多个线程的同时协助工作,多线程情况下,对于一些全局变量,也就是多个线程能够同时访问的变量,我们需要通过加锁来防止“同时”访问这个变量,Mutex 就是我们常用的一个。
frameworks/av/include/camera/CameraBase.h
113 Mutex mLock;frameworks/av/camera/Camera.cpp
214 void Camera::stopRecording()215 {216 ALOGV("stopRecording");217 {218 Mutex::Autolock _l(mLock);219 mRecordingProxyListener.clear();220 }221 sp <::android::hardware::ICamera> c = mCamera;222 if (c == 0) return;223 c->stopRecording();224 }例如上面的代码,首先会定义一个Mutex 对象mLock,在代码中对全局变量访问时,先要获取mLock,例如上面在操作mRecordingProxyListener 时,先通过Mutex::Autolock _l(mLock);获取这把锁,加了大括号是限制这个锁的作用域,离开这个作用域之后,这把锁会自动释放,下面会介绍。
system/core/include/utils/Mutex.h
100 pthread_mutex_t mMutex;
111 inline Mutex::Mutex() {112 pthread_mutex_init(&mMutex, NULL);113 }83 class Autolock {84 public:85 inline Autolock(Mutex& mutex) : mLock(mutex) { mLock.lock(); }86 inline Autolock(Mutex* mutex) : mLock(*mutex) { mLock.lock(); }87 inline ~Autolock() { mLock.unlock(); }88 private:89 Mutex& mLock;90 };131 inline status_t Mutex::lock() {132 return -pthread_mutex_lock(&mMutex);133 }134 inline void Mutex::unlock() {135 pthread_mutex_unlock(&mMutex);136 }128 inline Mutex::~Mutex() {129 pthread_mutex_destroy(&mMutex);130 }通过上面的代码我们知道 Mutex::Autolock _l(mLock) 获取锁和释放锁 是利用了C++ 类的构造函数和析构函数的特性实现的。在.h头文件里面定义 Mutex mLock; 的时候就已经调用了Mutex 的构造函数,进而调用到pthread_mutex_init()初始化pthread_mutex_t mMutex; 而Mutex::Autolock _l(mLock); 放在函数里面定义,是一个局部变量,也会调用Autolock 的构造函数,进而调用到Mutex::lock(); Autolock 对象 _l 跑出大括号后,也就是跑出它的作用域后,会调用它的析构函数,进而调用到Mutex::unlock() 释放锁。
Mutex 只是对对pthread_mutex_xxx()接口做了一层封装而已,真正的实现在pthread_mutex_xxx()接口。
pthread_mutex_xxx()声明在bionic/libc/include/pthread.h
39 typedef struct {40 #if defined(__LP64__)41 int32_t __private[10]; //长度为10的整形数组42 #else43 int32_t __private[1]; //长度为1 的整形数组44 #endif45 } pthread_mutex_t;
1、初始化函数pthread_mutex_init()
bionic/libc/bionic/pthread_mutex.cpp
241 int pthread_mutex_init(pthread_mutex_t* mutex_interface, const pthread_mutexattr_t* attr) {/* * struct pthread_mutex_internal_t { * _Atomic(uint16_t) state; //2 byte * #if defined(__LP64__) //64为定义是长度为10的整形数组, 40 byte * uint16_t __pad; //2 byte * atomic_int owner_tid; //4 byte * char __reserved[32]; //32 byte * #else //长度为1 的整形数组, 4 byte * _Atomic(uint16_t) owner_tid; //2 byte * #endif * } __attribute__((aligned(4)));*/242 pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);243 244 memset(mutex, 0, sizeof(pthread_mutex_internal_t)); //mutex 所有byte设置为 0245 246 if (__predict_true(attr == NULL)) { //没有设置相关属性时247 atomic_init(&mutex->state, MUTEX_TYPE_BITS_NORMAL); //mutex->state = (((0) & ((1 << (2))-1)) << (14)) 也就是0248 return 0;249 }... //因为针对上面的实现传入的attr 为NULL,所以这部分的代码先不做分析272 return 0;273 }
2、获取锁函数pthread_mutex_lock()
bionic/libc/bionic/pthread_mutex.cpp
503 int pthread_mutex_lock(pthread_mutex_t* mutex_interface) {504 #if !defined(__LP64__) //非64为系统505 if (mutex_interface == NULL) {506 return EINVAL;507 }508 #endif509 510 pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);511 512 uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed); //old_state = mutex->state513 uint16_t mtype = (old_state & MUTEX_TYPE_MASK); //mtype =old_state &(((1 << (2))-1) << (14)) 也就是mtype =old_state & 49152514 uint16_t shared = (old_state & MUTEX_SHARED_MASK);//shared =old_state &(((1 << (1))-1) << (13)) 也就是shared =old_state & 8192515 // Avoid slowing down fast path of normal mutex lock operation.516 if (__predict_true(mtype == MUTEX_TYPE_BITS_NORMAL)) { //MUTEX_TYPE_BITS_NORMAL =0517 if (__predict_true(__pthread_normal_mutex_trylock(mutex, shared) == 0)) {518 return 0; 519 }520 }521 return __pthread_mutex_lock_with_timeout(mutex, false, nullptr);522 }pthread_mutex_lock() 先判断 是否可以直接获取锁,没有其他线程在使用的时候可以获取,通过__pthread_normal_mutex_trylock()来实现
275 static inline __always_inline int __pthread_normal_mutex_trylock(pthread_mutex_internal_t* mutex,276 uint16_t shared) {277 const uint16_t unlocked = shared | MUTEX_STATE_BITS_UNLOCKED; //MUTEX_STATE_BITS_UNLOCKED = 0278 const uint16_t locked_uncontended = shared | MUTEX_STATE_BITS_LOCKED_UNCONTENDED; //MUTEX_STATE_BITS_LOCKED_UNCONTENDED = 16384279 280 uint16_t old_state = unlocked; //如果 mutex->state == old_state, mutex->state = locked_uncontended //否则 mutex->state = old_state281 if (__predict_true(atomic_compare_exchange_strong_explicit(&mutex->state, &old_state, //282 locked_uncontended, memory_order_acquire, memory_order_relaxed))) {283 return 0; 284 }285 return EBUSY;286 }__pthread_normal_mutex_trylock()会判读mutex->state 是否等于old_state,如果相等 ,将 mutex->state 的值设置成 locked_uncontended,否则设置成old_state 。
如果获取不到这个锁,就会往下走到__pthread_mutex_lock_with_timeout()。
421 static int __pthread_mutex_lock_with_timeout(pthread_mutex_internal_t* mutex,422 bool use_realtime_clock,423 const timespec* abs_timeout_or_null) {424 uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed); //old_state = mutex->state425 uint16_t mtype = (old_state & MUTEX_TYPE_MASK); //mtype =old_state &(((1 << (2))-1) << (14)) 也就是mtype =old_state & 49152426 uint16_t shared = (old_state & MUTEX_SHARED_MASK); //shared =old_state &(((1 << (1))-1) << (13)) 也就是shared =old_state & 8192427 428 // Handle common case first.429 if ( __predict_true(mtype == MUTEX_TYPE_BITS_NORMAL) ) { //MUTEX_TYPE_BITS_NORMAL = 0430 return __pthread_normal_mutex_lock(mutex, shared, use_realtime_clock, abs_timeout_or_null);431 }... //我们重点关注实现的流程,其他额外处理部分的代码先不分析501 }接着走到__pthread_normal_mutex_lock(), 传入的参数use_realtime_clock 为false,abs_timeout_or_null 为 nullptr
static inline __always_inline int __pthread_normal_mutex_lock(pthread_mutex_internal_t* mutex,301 uint16_t shared,302 bool use_realtime_clock,303 const timespec* abs_timeout_or_null) {304 if (__predict_true(__pthread_normal_mutex_trylock(mutex, shared) == 0)) { //前面解释过了305 return 0;306 }307 int result = check_timespec(abs_timeout_or_null, true); //这里会返回 0308 if (result != 0) {309 return result;310 }311 312 ScopedTrace trace("Contending for pthread mutex");313 314 const uint16_t unlocked = shared | MUTEX_STATE_BITS_UNLOCKED;315 const uint16_t locked_contended = shared | MUTEX_STATE_BITS_LOCKED_CONTENDED;316 317 // We want to go to sleep until the mutex is available, which requires318 // promoting it to locked_contended. We need to swap in the new state319 // and then wait until somebody wakes us up.320 // An atomic_exchange is used to compete with other threads for the lock.321 // If it returns unlocked, we have acquired the lock, otherwise another322 // thread still holds the lock and we should wait again.323 // If lock is acquired, an acquire fence is needed to make all memory accesses324 // made by other threads visible to the current CPU./* * atomic_exchange_explicit()执行的结果是mutex->state = locked_contended ,返回值是之前的 mutex->state * 所以这个条件可以理解成 uint16_t temp = mutex->state;mutex->state = locked_contended , temp != unlocked*/325 while (atomic_exchange_explicit(&mutex->state, locked_contended, 326 memory_order_acquire) != unlocked) { 327 if (__futex_wait_ex(&mutex->state, shared, locked_contended, use_realtime_clock,328 abs_timeout_or_null) == -ETIMEDOUT) {329 return ETIMEDOUT;330 }331 }332 return 0;333 }首先会重新去获取锁,调用__pthread_normal_mutex_trylock() 尝试去获取,前面有介绍这个函数,如果还是拿不到,会走到最后的while 里面,atomic_exchange_explicit() 的返回值是修改之前的mutex->state,也就是进入这个函数之前的mutex->state,如果状态不是unlocked,继续走到__futex_wait_ex(),
bionic/libc/private/bionic_futex.h
68 static inline int __futex_wait_ex(volatile void* ftx, bool shared, int value,69 bool use_realtime_clock, const struct timespec* abs_timeout) {70 return __futex(ftx, (shared ? FUTEX_WAIT_BITSET : FUTEX_WAIT_BITSET_PRIVATE) |71 (use_realtime_clock ? FUTEX_CLOCK_REALTIME : 0), value, abs_timeout,72 FUTEX_BITSET_MATCH_ANY);73 }继续调用__futex_wait_ex()
43 static inline __always_inline int __futex(volatile void* ftx, int op, int value,44 const struct timespec* timeout,45 int bitset) {46 // Our generated syscall assembler sets errno, but our callers (pthread functions) don't want to.47 int saved_errno = errno;48 int result = syscall(__NR_futex, ftx, op, value, timeout, NULL, bitset);49 if (__predict_false(result == -1)) {50 result = -errno;51 errno = saved_errno;52 }53 return result;54 }__futex_wait_ex()会调用到syscall()函数,是一个系统调用函数,所以接下里就跑到kernel。
linux-4.10/kernel/futex.c
3243 SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,3244 struct timespec __user *, utime, u32 __user *, uaddr2,3245 u32, val3)3246 {...3275 return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);3276 }
系统调用从user 空间切换到kernel 空间,前面的博客有详细介绍过,这里不再介绍,我们理所当然地认为就调用到了kernel 的do_futex()。
传入的参数uaddr 就是指向mutex->state 的地址,op 是FUTEX_WAIT/FUTEX_WAIT_BITSET, val 是上面的locked_contended,tp 是 NULL。
3185 long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,3186 u32 __user *uaddr2, u32 val2, u32 val3)3187 {3188 int cmd = op & FUTEX_CMD_MASK;...3211 switch (cmd) {3212 case FUTEX_WAIT:3213 val3 = FUTEX_BITSET_MATCH_ANY;3214 case FUTEX_WAIT_BITSET:3215 return futex_wait(uaddr, flags, val, timeout, val3); //原子检查uaddr 的值是否和val相等...3238 }3239 return -ENOSYS;3240 }根据前面参数的解释,我们知道上面的case 会走到 futex_wait()
2402 static int futex_wait(u32 __user *uaddr, unsigned int flags, u32 val,2403 ktime_t *abs_time, u32 bitset)2404 {2405 struct hrtimer_sleeper timeout, *to = NULL;2406 struct restart_block *restart;2407 struct futex_hash_bucket *hb;2408 struct futex_q q = futex_q_init;2409 int ret;2410 2411 if (!bitset)2412 return -EINVAL;2413 q.bitset = bitset;2414 2415 if (abs_time) {2416 to = &timeout;2417 2418 hrtimer_init_on_stack(&to->timer, (flags & FLAGS_CLOCKRT) ?2419 CLOCK_REALTIME : CLOCK_MONOTONIC,2420 HRTIMER_MODE_ABS);2421 hrtimer_init_sleeper(to, current);2422 hrtimer_set_expires_range_ns(&to->timer, *abs_time,2423 current->timer_slack_ns);2424 }2425 2426 retry:2427 /*2428 * Prepare to wait on uaddr. On success, holds hb lock and increments2429 * q.key refs.2430 */2431 ret = futex_wait_setup(uaddr, val, flags, &q, &hb); //2432 if (ret)2433 goto out;2434 2435 /* queue_me and wait for wakeup, timeout, or a signal. */2436 futex_wait_queue_me(hb, &q, to);2437 2438 /* If we were woken (and unqueued), we succeeded, whatever. */2439 ret = 0;2440 /* unqueue_me() drops q.key ref */2441 if (!unqueue_me(&q))2442 goto out;...2468 out:2469 if (to) {2470 hrtimer_cancel(&to->timer);2471 destroy_hrtimer_on_stack(&to->timer);2472 }2473 return ret;2474 }如果设置有超时,会挂到hrtimer(高精度实时定时器)上,这里没有设置,我们重点关注futex_wait_setup() 和futex_wait_queue_me()
static int futex_wait_setup(u32 __user *uaddr, u32 val, unsigned int flags,2344 struct futex_q *q, struct futex_hash_bucket **hb)2345 {2346 u32 uval;2347 int ret;...2367 retry:2368 ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &q->key, VERIFY_READ);2369 if (unlikely(ret != 0))2370 return ret;2371 2372 retry_private:2373 *hb = queue_lock(q);2374 2375 ret = get_futex_value_locked(&uval, uaddr);2376 2377 if (ret) {2378 queue_unlock(*hb);2379 2380 ret = get_user(uval, uaddr);2381 if (ret)2382 goto out;2383 2384 if (!(flags & FLAGS_SHARED))2385 goto retry_private;2386 2387 put_futex_key(&q->key);2388 goto retry;2389 }2390 2391 if (uval != val) {2392 queue_unlock(*hb);2393 ret = -EWOULDBLOCK;2394 }2395 2396 out:2397 if (ret)2398 put_futex_key(&q->key);2399 return ret;2400 }这个函数里面会比较mutex->state 和 val(locked_contended)是否相等,因为可能这时候有线程把锁释放了,不相等表示可以拿到锁了。
2294 static void futex_wait_queue_me(struct futex_hash_bucket *hb, struct futex_q *q,2295 struct hrtimer_sleeper *timeout)2296 {2297 /*2298 * The task state is guaranteed to be set before another task can2299 * wake it. set_current_state() is implemented using smp_store_mb() and2300 * queue_me() calls spin_unlock() upon completion, both serializing2301 * access to the hash list and forcing another memory barrier.2302 */2303 set_current_state(TASK_INTERRUPTIBLE); //可以被中断2304 queue_me(q, hb);2305 2306 /* Arm the timer */2307 if (timeout)2308 hrtimer_start_expires(&timeout->timer, HRTIMER_MODE_ABS);2309 2310 /*2311 * If we have been removed from the hash list, then another task2312 * has tried to wake us, and we can skip the call to schedule().2313 */2314 if (likely(!plist_node_empty(&q->list))) {2315 /*2316 * If the timer has already expired, current will already be2317 * flagged for rescheduling. Only call schedule if there2318 * is no timeout, or if it has yet to expire.2319 */2320 if (!timeout || timeout->task)2321 freezable_schedule(); //调用 schedule() 进行调度2322 }2323 __set_current_state(TASK_RUNNING);2324 }如果还是没有拿到锁,就会进入到上面的futex_wait_queue_me(),这个里面会把当前进程设置为可中断的,并且把当前task_structr放到 futex_q 中。
2022 static inline void queue_me(struct futex_q *q, struct futex_hash_bucket *hb)2023 __releases(&hb->lock)2024 {2025 int prio;2026 2027 /*2028 * The priority used to register this element is2029 * - either the real thread-priority for the real-time threads2030 * (i.e. threads with a priority lower than MAX_RT_PRIO)2031 * - or MAX_RT_PRIO for non-RT threads.2032 * Thus, all RT-threads are woken first in priority order, and2033 * the others are woken last, in FIFO order.2034 */2035 prio = min(current->normal_prio, MAX_RT_PRIO); //设置进程的优先级2036 2037 plist_node_init(&q->list, prio);2038 plist_add(&q->list, &hb->chain);2039 q->task = current;2040 spin_unlock(&hb->lock);2041 }把当前task_structr放到 futex_q 后,调用freezable_schedule() 做进程调度,所以这个进程就被调度出去了。
linux-4.10/include/linux/freezer.h168 static inline void freezable_schedule(void)169 {170 freezer_do_not_count();171 schedule();172 freezer_count();173 }走到这里,相当于当前进程陷入到kernel 的系统调用中,并且被调度出cpu的运行队列,放到futex_q 队列中。
3、释放锁函数pthread_mutex_unlock()
bionic/libc/bionic/pthread_mutex.cpp
524 int pthread_mutex_unlock(pthread_mutex_t* mutex_interface) {525 #if !defined(__LP64__)526 if (mutex_interface == NULL) {527 return EINVAL;528 }529 #endif530 531 pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);532 533 uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);534 uint16_t mtype = (old_state & MUTEX_TYPE_MASK);535 uint16_t shared = (old_state & MUTEX_SHARED_MASK);536 537 // Handle common case first.538 if (__predict_true(mtype == MUTEX_TYPE_BITS_NORMAL)) {539 __pthread_normal_mutex_unlock(mutex, shared);540 return 0;541 }...571 return 0;572 }如前面描述的,跑出作用域后,会释放这个锁,继而调用到pthread_mutex_unlock()
339 static inline __always_inline void __pthread_normal_mutex_unlock(pthread_mutex_internal_t* mutex,340 uint16_t shared) {341 const uint16_t unlocked = shared | MUTEX_STATE_BITS_UNLOCKED;342 const uint16_t locked_contended = shared | MUTEX_STATE_BITS_LOCKED_CONTENDED;343 344 // We use an atomic_exchange to release the lock. If locked_contended state345 // is returned, some threads is waiting for the lock and we need to wake up346 // one of them.347 // A release fence is required to make previous stores visible to next348 // lock owner threads.349 if (atomic_exchange_explicit(&mutex->state, unlocked,350 memory_order_release) == locked_contended) {351 // Wake up one waiting thread. We don't know which thread will be352 // woken or when it'll start executing -- futexes make no guarantees353 // here. There may not even be a thread waiting.354 //355 // The newly-woken thread will replace the unlocked state we just set above356 // with locked_contended state, which means that when it eventually releases357 // the mutex it will also call FUTEX_WAKE. This results in one extra wake358 // call whenever a lock is contended, but let us avoid forgetting anyone359 // without requiring us to track the number of sleepers.360 //361 // It's possible for another thread to sneak in and grab the lock between362 // the exchange above and the wake call below. If the new thread is "slow"363 // and holds the lock for a while, we'll wake up a sleeper, which will swap364 // in locked_uncontended state and then go back to sleep since the lock is365 // still held. If the new thread is "fast", running to completion before366 // we call wake, the thread we eventually wake will find an unlocked mutex367 // and will execute. Either way we have correct behavior and nobody is368 // orphaned on the wait queue.369 __futex_wake_ex(&mutex->state, shared, 1);370 }371 }__pthread_normal_mutex_unlock()会判断当前线程是否还持有这个锁,如果是,会调用到__futex_wake_ex()
bionic/libc/private/bionic_futex.h
60 static inline int __futex_wake_ex(volatile void* ftx, bool shared, int count) {61 return __futex(ftx, shared ? FUTEX_WAKE : FUTEX_WAKE_PRIVATE, count, NULL, 0);62 }
43 static inline __always_inline int __futex(volatile void* ftx, int op, int value,44 const struct timespec* timeout,45 int bitset) {46 // Our generated syscall assembler sets errno, but our callers (pthread functions) don't want to.47 int saved_errno = errno;48 int result = syscall(__NR_futex, ftx, op, value, timeout, NULL, bitset);49 if (__predict_false(result == -1)) {50 result = -errno;51 errno = saved_errno;52 }53 return result;54 }
又是系统调用,这里我们直接跳到kernel 的 do_futex()
linux-4.10/kernel/futex.c
3185 long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,3186 u32 __user *uaddr2, u32 val2, u32 val3)3187 {3188 int cmd = op & FUTEX_CMD_MASK;...3211 switch (cmd) {...3216 case FUTEX_WAKE:3217 val3 = FUTEX_BITSET_MATCH_ANY;3218 case FUTEX_WAKE_BITSET:3219 return futex_wake(uaddr, flags, val, val3);...3238 }3239 return -ENOSYS;3240 }传入的参数uaddr 指向&mutex->state,op 为FUTEX_WAKE / FUTEX_WAKE_PRIVATE ,val等于 1,接着跑到futex_wake()
1411 static int1412 futex_wake(u32 __user *uaddr, unsigned int flags, int nr_wake, u32 bitset)1413 {1414 struct futex_hash_bucket *hb;1415 struct futex_q *this, *next;1416 union futex_key key = FUTEX_KEY_INIT;1417 int ret;1418 DEFINE_WAKE_Q(wake_q);1419 1420 if (!bitset)1421 return -EINVAL;1422 1423 ret = get_futex_key(uaddr, flags & FLAGS_SHARED, &key, VERIFY_READ);1424 if (unlikely(ret != 0))1425 goto out;1426 1427 hb = hash_futex(&key);1428 1429 /* Make sure we really have tasks to wakeup */1430 if (!hb_waiters_pending(hb))1431 goto out_put_key;1432 1433 spin_lock(&hb->lock);1434 1435 plist_for_each_entry_safe(this, next, &hb->chain, list) {1436 if (match_futex (&this->key, &key)) {1437 if (this->pi_state || this->rt_waiter) {1438 ret = -EINVAL;1439 break;1440 }1441 1442 /* Check if one of the bits is set in both bitsets */1443 if (!(this->bitset & bitset))1444 continue;1445 1446 mark_wake_futex(&wake_q, this);1447 if (++ret >= nr_wake)1448 break;1449 }1450 }1451 1452 spin_unlock(&hb->lock);1453 wake_up_q(&wake_q); //唤醒队列中的task_struct 1454 out_put_key:1455 put_futex_key(&key);1456 out:1457 return ret;1458 }根据上传下来的值知道nr_wake 为1,所以mark_wake_futex()只会跑一次。
1272 static void mark_wake_futex(struct wake_q_head *wake_q, struct futex_q *q)1273 {1274 struct task_struct *p = q->task;1275 1276 if (WARN(q->pi_state || q->rt_waiter, "refusing to wake PI futex\n"))1277 return;1278 1279 /*1280 * Queue the task for later wakeup for after we've released1281 * the hb->lock. wake_q_add() grabs reference to p.1282 */1283 wake_q_add(wake_q, p);1284 __unqueue_futex(q);1285 /*1286 * The waiting task can free the futex_q as soon as1287 * q->lock_ptr = NULL is written, without taking any locks. A1288 * memory barrier is required here to prevent the following1289 * store to lock_ptr from getting ahead of the plist_del.1290 */1291 smp_wmb();1292 q->lock_ptr = NULL;1293 }mark_wake_futex() 就是把要唤醒的task_struct 放入wake_q 队列中 ,wake_q_add() ,最后调用wake_up_q(&wake_q); 来唤醒(调度)task_struct, 所以前面获取锁的系统调用就会返回。
4、销毁mutex pthread_mutex_destroy()
bionic/libc/bionic/pthread_mutex.cpp
634 int pthread_mutex_destroy(pthread_mutex_t* mutex_interface) {635 pthread_mutex_internal_t* mutex = __get_internal_mutex(mutex_interface);636 uint16_t old_state = atomic_load_explicit(&mutex->state, memory_order_relaxed);637 // Store 0xffff to make the mutex unusable. Although POSIX standard says it is undefined638 // behavior to destroy a locked mutex, we prefer not to change mutex->state in that situation.639 if (MUTEX_STATE_BITS_IS_UNLOCKED(old_state) && //old_state & 49152 == 0640 atomic_compare_exchange_strong_explicit(&mutex->state, &old_state, 0xffff,641 memory_order_relaxed, memory_order_relaxed)) {642 return 0;643 }644 return EBUSY;645 }如果没有线程在使用,就把mutex->state 设置成0xffff ,表示不可用了
阅读全文