pthread_cond_timedwait的基本步骤如下:
1. Acquire the mutex lock (before calling pthread_cond_timedwait).
2. Acquire the cond lock.
3. Release the mutex lock.
4. Modify the cond data.
5. Release the cond lock.
6. Execute futex_wait.
7. woken up by other thread.
8. Re-acquire the cond lock.
9. Compare the cond data to determine if the current thread was woken up normally or due to a timeout, and whether it needs to wait again.
10. Modify the cond data.
11. Release the cond lock.
12. Re-acquire the mutex lock.
13. Release the mutex lock (after calling pthread_cond_timedwait).
为什么需要 cond 锁,而不是只使用互斥锁?也就是说:
1. Acquire the mutex lock (before calling pthread_cond_timedwait).
2. Modify the cond data.
3. Release the mutex lock.
4. Execute futex_wait.
5. woken up by other thread.
6. Re-acquire the mutex lock.
7. Compare the cond data to determine if the current thread was woken up normally or due to a timeout, and whether it needs to wait again.
8. Modify the cond data.
9. Release the mutex lock (after calling pthread_cond_timedwait).
Pthreads 未指定存在与 pthreads 条件变量固有关联的任何类型的锁。 它没有指定问题中提出的详细步骤。 如果某个特定的实现这样做了,那么这是由于该实现本身的原因。
但是,假设某些实现的
pthread_cond_timedlock()
的行为确实如所描述的那样,我们可以考虑为什么会这样。 让我们假设它已被正确编程,没有不必要的锁定。 为什么仅仅依靠传递给 pthread_cond_timedlock()
的互斥体来保护对 CV 状态的访问是不够的?
答案(至少)有三重:
某些 CV 操作不需要在互斥锁的保护下执行。 特别是,在调用
pthread_cond_signal()
或 pthread_cond_broadcast()
时,不需要锁定任何特定的互斥体。
即使
pthread_cond_wait()
和 pthread_cond_timedwait()
原则上也可以在不同时间使用不同的互斥体进行调用,只要同一 CV 上的并发等待不会使用不同的互斥体即可。
如果 CV 访问需要锁保护,那么 所有 访问都需要这种保护,并且只有当所有访问都使用 相同 锁时它才有效。 这需要一个与 CV 关联的锁,独立于互斥锁(如果有的话),它在任何给定时间动态关联。
根据规格:
这些函数以原子方式释放
并导致调用线程在条件变量mutex
上阻塞;原子地在这里意味着“原子地相对于另一个线程访问互斥体然后访问条件变量”。也就是说,如果另一个线程能够在即将阻塞的线程释放互斥锁后获取该互斥锁,则该线程中对cond
或pthread_cond_broadcast()
的后续调用的行为将如同在即将阻塞的线程之后发出一样。待阻塞线程已阻塞。pthread_cond_signal()
确保符合该要求可能需要在互斥体之上和之外使用锁或类似的辅助工具。