1. 利用原子操作控制变量 uint32_t futex ,控制不同的线程抢占。
      • futex = 0 ,说明无人抢占。
      • futex = 1 ,只有一个线程抢占(拿到了锁)。
        • 其它线程看到 futex 不等于 0 时 ,需要原子设置 futex=2,标记抢占;同时检查设置后获取的 old value ,如果不为0,说明有人先一步抢占,自己需要 wait 。
      • futex = 2 ,有线程抢占和等待。
        • 此时也需要原子设置 futex=2,检查设置后获取的 old value ,判断自己是不是先一步抢占到。如果不为0,需要wait。
      • 抢占锁的线程 释放锁时,调用 futex_wake 唤醒 futex 变量上的线程。
    2. 利用 futex_wait / futex_wake 控制线程等待和唤醒。
    1. atomic_compare_and_exchange_bool_acq(mem, newval, oldval)
    2. : 如果交换成功,返回0,失败返回非0
    3. /* Atomically store NEWVAL in *MEM if *MEM is equal to OLDVAL.
    4. Return zero if *MEM was changed or non-zero if no exchange happened. */
    5. atomic_exchange_acq(mem, newvalue):
    6. /* Store NEWVALUE in *MEM and return the old value. */
    7. futex_wait, futex_wake 是系统调用。
    8. // uaddr指向一个地址,val代表这个地址期待的值,当*uaddr==val时,才会进行wait
    9. int futex_wait(int *uaddr, int val);
    10. // 唤醒n个在uaddr指向的锁变量上挂起等待的进程
    11. int futex_wake(int *uaddr, int n);
    12. # define LLL_MUTEX_LOCK(mutex) \
    13. lll_lock ((mutex) ->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex))
    14. lock(mutex)
    15. {
    16. /* Normal mutex. */
    17. LLL_MUTEX_LOCK (mutex);
    18. /* 等价于: lll_lock ((mutex) ->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex)) */
    19. /* Record the ownership. */
    20. mutex->__data.__owner = id;
    21. #ifndef NO_INCR
    22. ++mutex->__data.__nusers;
    23. #endif
    24. }
    25. void lll_lock(uint32_t* futex)
    26. {
    27. /* 成功设置为 1 时返回 0 ,表示第一次有人 lock;失败返回非0,说明有人用了
    28. 1. 期望是 old value = 0, 设置 new value = 1,抢占 futex。
    29. 2. 如果有人用了(value=1, 或者 2) ,就需要进入 wait
    30. */
    31. if (atomic_compare_and_exchange_bool_acq(futex, 1, 0/* old value */)) {
    32. lock_wait(futex);
    33. }
    34. }
    35. void lock_wait(uint32_t*futex)
    36. {
    37. if (*futex == 2) { /* 小优化: 快速进入 wait*/
    38. futex_wait(futex, 2);
    39. }
    40. /* 有3种返回值: =0 时,无人占用。 =1 时,有其它人抢占。 =2 时,有其它人抢占和等待。
    41. 如果 atomic_exchange_acq 返回值是0,说明自己是第一个设置 futex=2,可以推出 wait。
    42. 1. 设置 futex = 2, atomic_exchange_acq 返回非0(1,2),进入 wait;否则推出循环。
    43. 2. 每次唤醒时,重复设置 futex = 2,尝试抢占。
    44. */
    45. while (atomic_exchange_acq(futex, 2)) {
    46. futex_wait(futex, 2);
    47. }
    48. }
    49. void unlock(mutex) {
    50. mutex->__data.__owner = 0;
    51. if (decr)
    52. /* One less user. */
    53. --mutex->__data.__nusers;
    54. /* Unlock. */
    55. lll_unlock (mutex->__data.__lock, PTHREAD_MUTEX_PSHARED (mutex));
    56. }
    57. void lll_unlock(uint32_t* futex)
    58. {
    59. int oldval = atomic_exchange_acq(futex, 0);
    60. /* 如果仍旧为 1 ,说明之前没人来 lock,只有自己在用,可以不调用 wake 。
    61. 1. 解锁时,直接设置为0,同时获取 old value。
    62. 2. 如果 old value > 1 (实际是等于2),说明有人在 wait
    63. */
    64. if (__unlikely(oldval > 1)) {
    65. futex_wake(futex, 1/* number of waiters */);
    66. }
    67. }