锁中的唤醒/等待竞赛?

Rag*_*thy 6 multithreading operating-system locks

我正在阅读 Remzi 教授的 OSTEP 书 http://pages.cs.wisc.edu/~remzi/OSTEP/

我只能部分理解以下代码如何导致唤醒/等待竞争条件。(代码取自书籍章节。http: //pages.cs.wisc.edu/~remzi/OSTEP/threads-locks.pdf

void lock(lock_t *m) {
    while (TestAndSet(&m->guard, 1) == 1); //acquire guard lock by spinning
        if (m->flag == 0) {
            m->flag = 1; // lock is acquired
            m->guard = 0;
        } else {
           queue_add(m->q, gettid());
           m->guard = 0;
           park();  
        }
    }
}

void unlock(lock_t *m) {
    while (TestAndSet(&m->guard, 1) == 1); //acquire guard lock by spinning
        if (queue_empty(m->q))
            m->flag = 0; // let go of lock; no one wants it
        else
            unpark(queue_remove(m->q)); // hold lock (for next thread!)
        m->guard = 0;
}
Run Code Online (Sandbox Code Playgroud)

Park() 系统调用将调用线程置于睡眠状态,而 unpark(threadID) 用于唤醒由 threadID 指定的特定线程。

现在如果线程1通过将m->flag设置为1来持有锁。如果线程2进来获取锁,则失败。因此,执行 else 情况,并将 thread2 添加到队列中,但假设-if在进行 park() 系统调用之前,thread2 被调度出去,并且 thread1 被给予时间片。如果线程1释放锁,unlock函数会尝试调用unpark系统调用(队列非空),因为线程2在队列中。但是thread2没有调用park()系统调用,它只是被添加到队列中。

所以问题
1) thread1 的 unpark() 返回什么,只是一个错误说找不到 threadID?(特定于操作系统)
2)锁标志会发生什么?它应该在调用锁例程的后续线程之间传递,仅当不再有锁争用时才释放锁。

上说 thread2 将永远休眠。但我的理解是任何争夺锁的后续线程都将永远休眠,比如线程3稍后尝试获取锁,因为在解锁调用期间锁永远不会被线程1释放。

我的理解很可能是错误的,因为这本书非常具体地指出 thread2 永远休眠。或者我只是在例子中读了太多而我的理解是正确的?!!!并且出现僵局?

Rag*_*thy 2

将此问题邮寄给Remzi教授并得到了他的答复!只是在这里发布回复。

Remzi教授的回复:

好问题!

我认为你基本上是对的。

unpark() 将返回(也许会说 threadID 没有休眠);在此实现中,锁保持锁定状态,并且 thread2 将永远休眠,正如您所说,所有尝试获取锁的后续线程将无法这样做。