我读了ostep书。我停在关于线程锁的章节上。通过 futex 实现互斥:
void mutex_lock(int *mutex)
{
int v;
if (atomic_bit_test_set(mutex, 31) == 0)
return;
atomic_increment(mutex);
while(1)
{
if (atomic_bit_test_set(mutex, 31) == 0)
{
atomic_decrement(mutex);
return;
}
v = *mutex;
if (v >= 0)
continue;
futex_wait(mutex, v);
}
}
void mutex_unlock(int *mutex)
{
if (atomic_add_zero(mutex, 0x80000000)) // (1)
return;
// <-- (here)
futex_wake(mutex); // (2)
}
我不明白为什么我们需要这三行:
v = *mutex;
if (v >= 0)
continue;
让我们考虑所有的可能性。什么时候可以呢?如果某个线程(第一个)获取了锁并想要释放它,则另一个线程(第二个)处于 while 循环中,如果是这样 => (1) 情况不能,因为在循环外我们增加互斥量,这意味着我们在(这里)并且 *mutex 现在 >= 0 => 调度程序中断 第一个线程(此处)并切换到第二个线程,我认为只有在这种情况下我们才需要这些行(我不知道其他可能性),但为什么我们不能删除它们?如果我们删除它们,第二个线程就会进入睡眠状态,例如futex 队列,当调度程序切换到第一个线程时,他会唤醒第二个线程 (2)。
因为无论如何你都必须将值传递给
futex_wait
,所以你不妨在那里再做一次机会主义检查。
仅当 *mutex 的值没有从 v 改变时,futex_wait 系统调用才会挂起线程。