线程基础之遗漏和扩展部分

原文地址  译文地址   译者:姚志彬  校对:丁一,方腾飞

       这里我们只是关注了一些多线程之间共享变量的简单使用问题。这些是任何一个写多线程程序的人,都应该熟悉的最基础的问题。我们忽略了一些其他多线程实现提供的工具。它们虽然很少被用到,但是对于你的程序仍然很有必要。

其他锁类型

大多数环境提供可重入锁,即被一个单线程多次持有,比如java synchronized 块就有这种锁的特性行为。通常读写锁也提供这个功能,即一个锁可以同时被多个“读”线程持有,但只能同时被一个“写”线程持有。

条件变量等

对于一个线程等待某个特殊条件符合要求,条件变量时最普遍的机制,比如等待一个共享队列是不为空的。这些提供wait()调用来释放并且重新获取一个锁,挂起线程一段时间,直到它被另个线程唤醒(”notified” or signalled”)。如果一个线程不能被正确唤醒,条件变量很容易引入死锁到应用程序。因此它们应该被谨慎的运用。但如果我们的关注点只是我们的程序而不是产生的错误结果,一个wait(cv, lock)调用行为就如同一个unlock(lock)加lock(lock)的序列。​从而新的问题与这篇文章非常正交。

非阻塞锁获取

大多数语言或者线程库提供一个trylock()原函数,可以获得一个锁,像lock()的功能​,或者返回一个错误的提示,但它从来不会阻塞,这非常容易被我们的模型容纳,我们允许trylock()返回一个错误的提示,即使这个锁是可获得,或者至少是我们代码的原因,虽然这有可能发生。​ 因为一些微妙的原因这个假设不允许通过程序实现 ,否则可以看出顺序一致性的错觉 ,​类似观察申请锁时调用超时。实际上,不允许在代码中滥用trylock(),并且应该去用其他一些原语。

从顺序一致性“逃离”

很多语言允许通过侵犯顺序一致性来获取同步变量,即使程序不包含数据竞争。很多平台用这些来显著提升性能,以一个更复杂的程序模型为代价,在这里我们不讨论该问题。例如java.util.concurrent.atomic‘s lazySet() (Java 6 +) and weakCompareAndSet() 允许一些实现以和顺序一致性违背的方式来进行重排序​。C++0x atomic objects 支持内存排序限定参数的操作,它们大部分和顺序一致性违背。

历史和致谢

顺序一致性概念是被Lamport引入的,How to Make a Multiprocessor Computer that Correctly Executes Multiprocess Programs.​ sequential-consistency-for-data-race-free-programs方式从一开始就已经是​Ada编程模型的​基础。它作为一个被机器架构有效支撑的模型大约20年前​被Sarita Adve​研究的更详细。(See for example Adve and Hill, Weak Ordering – A New Definition, ISCA 1990.) ​如我们以上所指出的,Posix线程模型至少和它相似,但是很多Posix使用者不知道这一点。​​我们相信windows native 线程模型也是取向和它类似,但是直到最近还没有关于该主题的很多讨论。

最近几年java和C++0x内存模型是明确的基于这种方式实现的。​除了这些方面的论文作者,还有主要的贡献者包括Lawrence Crowl, Doug Lea, Paul McKenney, Clark Nelson, Bratin Saha, and Herb Sutter.​

Paul McKenney也发表了一篇​“frequently asked questions”文章,内容和这篇文章类似。​Sarita Adve在实现章节提供一些内容​。我们也借用了Herb Sutter例子。

很多读者在早期的草稿中​提供了有用的评论。​Rob Schreiber提供了特殊的扩展。

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/119728.html

(0)
上一篇 2021年8月28日 09:44
下一篇 2021年8月28日 09:48

相关推荐

发表回复

登录后才能评论