在简评:并发问题的牛鼻子》中我阐述了 concurrency problem 的核心来自于 shared data,而其解决方案也相当自然,即:根据不同的粒度,将 concurrent part 变为 serialized part(例如,通过 lock、通过 blocking queue 来实现)。这一说法本身并没有错,但这只是 concurrency problem 的 half story:将关于 shared data 的「并发」部分「顺序化」。但这里还存在着另外一个问题,无论对于「加锁」还是使用 blocking queue,那些“加锁失败”或者“被 blocking”而处于“等待状态”的 thread 应该怎么办?它们如何被管理,又如何被唤醒?即:thread coordination 应该如何被实现?
为什么我们需要关心 thread coordination?难道它们不是被 lib 或者 OS(Operating System)去自动实现的吗?这取决于你的问题本身是否需要更为精细的 thread management。例如,常见于 concurrency 中的一个题目是:可以让两个 thread 交替打印 0 和 1 吗?此时,仅仅依靠对 lock 的认知而对 thread coordination 的实现机制毫不关心的话将直接导致你无法完成这个任务。更何况,现实中需要对某几个 thread 做 coordination 的问题会远远复杂于这道简单的题目。
事实上,要真正理解 thread coordination,就需要透彻地理解 thread 是什么,特别是,什么是关于 thread 的 scheduling,什么是 thread 的 blocking(详见thread/process 的错误直观》中的阐述)。简单来讲即是,虽然 thread 本身对于 OS program 来讲是 executor,但它对于 CPU 来讲却是 task,它仅仅是 CPU 的 basic scheduling unit task。所以,所谓的 thread blocking,并非是让 CPU 停止运转,而是将该 thread 标记为 sleep 状态,让 CPU 不去执行该 thread。从而对于这个 thread 所包含的 OS program 来讲,它的 executor 似乎是被直接停止了。于是,所谓的 thread coordination 其实就是各个 thread 根据自己的 thread state 去修改其它与之协作的 thread 的 state,从而间接实现 threadA 的 behavior 触发 threadB 的 state 改变。
显然,最直观的管理 waiting threads 的 data structure 是 queue。
而使用 waiting queue 的最简单的情景是关于 lock 的获取:一堆 thread 尝试去获取锁,而根据这......
阅读全文