就我理解的而言,被volatile修饰的共享变量,就具有了以下两点特性:
1 . 保证了不同线程对该变量操作的内存可见性;
2 . 禁止指令重排序
临界区( critical section)是访问共享资源的一段代码,资源通常是一个变量或数据结构
竞态条件( race condition)出现在多个执行线程大致同时进入临界区时,它们都试图更新共享 的数据结构,导致了令人惊讶的(也许是不希望的)结果。
不确定性( indeterminate)程序由一个或多个竞态条件组成,程序的输出因运行而异,具体取 决于哪些线程在何时运行。这导致结果不是确定的( deterministic),而我们通常期望计算机系统给出确 定的结果。
因此,我们要做的是要求硬件提供一些有用的指令,可以在这些指令上构建一个通用 的集合,即所谓的同步原语(synchronization primitive)。通过使用这些硬件同步原语,加上 操作系统的一些帮助,我们将能够构建多线程代码,以同步和受控的方式访问临界区,从 而可靠地产生正确的结果。
1.就好像线程之间只有一种交互,即访问共享变量,因此需要为临界区支持原子性。
2.事实证明,还有另一种常见的交互,即一个线程在继续之前必须等待另一个线程完成某些操作。 例如, 当进程执行磁盘 I/O 并进入睡眠状态时, 会产生这种交互。 I/O 完成时,该进程需要从睡眠中唤醒,以便继续进行。
因此,在接下来的章节中,我们不仅要研究如何构建对同步原语的支持来支持原子性,还要研究支持在多线程程序中常见的睡眠/唤醒交互的机制 (条件变量)。
原子操作是构建计算机系统的最强大的基础技术之一,从计算机体系结构到并行代码(我们在这里 研究的内容)、文件系统(我们将很快研究)、数据库管理系统,甚至分布式系统[L+93]。将一系列动作原子化( atomic)背后的想法可以简单用一个短语表达: “全部或没有”。看上去,要 么你希望组合在一起的所有活动都发生了,要么它们都没有发生。不会看到中间状态。有时,将许多行 为组合为单个原子动作称为事务( transaction),这是一个在数据库和事务处理世界中非常详细地发展的 概念[GR92]。在探讨并发的主题中,我们将使用同步原语,将指令的短序列变成原子性的执行块。