如果条件 1 满足就使用 CAS 减去 X_LOCK_DECR, 然后等待lock_word的值为 0.
如果条件 1 不满足, 则判断是否可以递归加锁, 即在申请 X 锁之前是否已经持有了 SX 或者 X 锁.
如果该线程之前已经持有了 SX 锁, 则将lock_word的值减去 X_LOCK_DECR, 然后等待lock_word的值为 -X_LOCK_HALF_DECR, 因为 SX 锁和 S 锁兼容, 所以由 SX 锁升级为 X 锁后, 需要等待其他线程持有的 S 锁释放.
如果该线程之前已经持有了 X 锁, 则修改lock_word后即可.
上述条件都不满足, 即其他线程可能持有了 SX 锁或者 X 锁, 则进入 spin 的等待状态.
UNIV_INLINE bool rw_lock_x_lock_low( rw_lock_t *lock, /*!< in: pointer to rw-lock */ ulint pass, /*!< in: pass value; != 0, if the lock will be passed to another thread to unlock */ const char *file_name, /*!< in: file name where lock requested */ ulint line) /*!< in: line where requested */ { if (rw_lock_lock_word_decr(lock, X_LOCK_DECR, X_LOCK_HALF_DECR)) { /* 1. 如果当前不存在 S 锁或者 SX 锁或者其他 X 锁, 步骤 1 是满足的, * 步骤 2 也无需等待直接返回加锁成功. */ rw_lock_set_writer_id_and_recursion_flag(lock, !pass);
/* 2. 如果这个锁已经被其他线程加了数量小于 X_LOCK_HALF_DECR 个 S 锁, * 步骤 1 也是满足的, 但是步骤 2 需要进入等待逻辑直到所有的 S 锁释放, * 即使当前读写锁上已经有其他的 S 锁, 但是为了防止 X 锁饥饿状态, * 所以将 X 预先分配给申请线程. */ rw_lock_x_lock_wait(lock, pass, 0, file_name, line);
/* The existing X or SX lock is from this thread */ if (rw_lock_lock_word_decr(lock, X_LOCK_DECR, 0)) { /* 之前已经持有了 SX 锁, 由 SX 锁升级为 X 锁. */ rw_lock_x_lock_wait(lock, pass, -X_LOCK_HALF_DECR, file_name, line);
如果条件 1 满足就使用 CAS 减去 X_LOCK_DECR, 因为 SX 锁和 S 锁兼容, 所以无需等待 lock_word 的值为 0.
如果条件 1 不满足, 则判断是否可以递归加锁, 即在申请 X 锁之前是否已经持有了 SX 或者 X 锁.
如果该线程之前已经成功申请了一个 X 锁, 所以 lock_word -= X_LOCK_HALF_DECR.
上述条件都不满足, 即 SX 或者 X 锁已经被其他线程持有, 则进入 spin 的等待状态.
bool rw_lock_sx_lock_low( rw_lock_t *lock, /*!< in: pointer to rw-lock */ ulint pass, /*!< in: pass value; != 0, if the lock will be passed to another thread to unlock */ const char *file_name, /*!< in: file name where lock requested */ ulint line) /*!< in: line where requested */ { if (rw_lock_lock_word_decr(lock, X_LOCK_HALF_DECR, X_LOCK_HALF_DECR)) { /* 1. 判断当前的 lock_word 是否大于 X_LOCK_HALF_DECR. * 2. 如果条件 1 满足就使用 CAS 减去 X_LOCK_DECR, 因为 SX 锁和 S 锁兼容, * 所以无需等待 lock_word 的值为 0. */
/* lock->recursive == true implies that the lock->writer_thread is the current writer. As we are going to write our own thread id in that field it must be the case that the current writer_thread value is not the current writer anymore, thus recursive flag must be false. */ ut_a(!lock->recursive.load(std::memory_order_relaxed));
/* Decrement occurred: we are the SX lock owner. */ rw_lock_set_writer_id_and_recursion_flag(lock, !pass);