《Haskell并行与并发编程》中waitEither实现的潜在死锁疑问
waitEither的MVar执行顺序与readMVar假设解答
1. 分支putMVar与主线程readMVar内putMVar的执行顺序
不可能出现主线程readMVar内的putMVar先于分支putMVar执行的情况,反过来,分支的putMVar必然先于主线程readMVar里的putMVar执行。
原因很直接:
- 主线程调用
wait (Async m)后,最终会进入readMVar m的逻辑,第一步就是takeMVar m。此时m是空的,主线程会阻塞,直到某个分支线程执行putMVar m填充它。 - 只有当分支的
putMVar m执行完成,主线程才能从takeMVar m中返回,进而执行后续的putMVar m(把值放回MVar)。
所以分支的putMVar是主线程完成takeMVar的前提,必然先于主线程readMVar内的putMVar执行。
2. 是否沿用官方readMVar的“接收下一个putMVar调用”假设
需要沿用这个假设,因为给定的readMVar实现完全符合官方语义:
- 官方文档中“会接收下一个putMVar调用”的核心保证是:当多个线程对同一个MVar调用
readMVar时,它们会依次通过takeMVar获取值、putMVar放回值,不会丢失后续putMVar写入的内容。 - 我们的
readMVar实现就是标准的takeMVar后紧跟putMVar,完全满足这个语义。即使在waitEither的场景中,主线程的readMVar会把m重新置为满状态,后续分支的putMVar m会阻塞,直到有其他线程再次takeMVar,这也完全符合官方语义的预期。
内容的提问来源于stack exchange,提问作者Sourabh
相关产品推荐
相关产品推荐

