您的位置:首页 > 理论基础

如何制造一台正确执行多进程程序的多处理器计算机?

2015-07-03 19:16 295 查看
原文标题:How to Make a Multiprocessor Computer That Correctly Executes Multiprocess Programs

原文作者:Lamport, Leslie (1979). 向先驱致敬!

摘要-许多大型顺序化计算机在执行操作时并不是按照程序中所指定的顺序来执行。如果按照某种

顺序执行的结果和按照程序中所指定的顺序执行的结果相同,那么就是正确的执行。对于一台多处理器

计算机,每个处理器的这种正确执行并不能保证整个程序的正确执行,需要增加额外的条件来保证多进

程程序的正确执行。

一个高速处理器执行操作的顺序可能不同于程序所指定的顺序。如果满足下述条件,就能保证执行的

正确性:执行的结果和按照程序中所指定的顺序执行的结果相同。一个满足这种条件的处理器被称为顺序化

。对于一台由多个这种处理器构成的共享内存计算机,通常在设计和证明多进程算法[1]-[3]执行的正确

性时假定以下条件成立:任何执行结果均是相同的,就好像所有处理器上执行的全部操作从总体上看是

某种顺序化的顺序执行;而且,每个处理器上所执行的操作在总的执行顺序中出现的顺序同该处理

器上该程序所指定的顺序保持一致。满足这种限制条件的多个处理器被称为顺序一致性。每个单一处理器的

顺序性不能保证多处理器计算机就是顺序一致性。为简单起见,以下描述一种方法使得通过共享内存互联的多个

个顺序化处理器能够实现顺序一致性。

给定一个由多个处理器和内存模块构成的多处理器计算机且处理器之间只能通过内存模块进行通信。(任何

用作通信的特殊寄存器可视为独立的内存模块)。唯一需要关注的处理器操作是发往内存模块的存和取数据请求,

假设每个处理器发起一系列的存取请求(有时必须要等待请求完成执行,但这不是关注点)。

以下通过实现两个简单进程互斥的协议来阐述多处理器顺序一致性的问题,每个进程均有一个临界区,协议

要保证任意时刻只有一个进程能执行临界区代码。协议如下:

process 1

a := 1;

if b = 0 then critical section;

a := 0

else ... fi

process 2

b := 1;

if a = 0 then critical section;

b := 0

else ... fi

else 语句中有一些机制用于保证最终能够访问到临界区,但这和要讨论的主题不相关。很容易证明该协议能

够保证互斥的访问临界区,因而当满足顺序一致性的多处理器计算机在执行这2个进程时,执行进程

的两个处理器必然不能同时执行临界区。

值得注意的是对于一个顺序化处理器,可能以任意的顺序执行process 1中的"a:=1"和"fetch
b",

(当仅从 process 1 自身的角度考虑,以何种顺序执行这两个操作无关紧要)。然而,很容易发现

当"fetch b"先执行时会导致错误--两个进程能同时执行它们各自的临界区代码。这令人马上想到一个

约束多处理器计算机的条件。

约束条件R1:每个处理器都必须按照它所执行的程序中指定的操作顺序来发起内存请求。

满足条件R1的复杂性在于存储一个value的前提条件是该value已经完成计算。处理器经常在尚未

得知前一个数据存储请求欲存储的value时就已经处于发起读取该value的就绪状态。为了最小化等待

时间,处理器在发起存储请求时可以不指定要存储的数据,而内存模块在接收到要存储的数据前并不

真正的去执行这种存储请求。

约束条件R1对于保证正确的执行仍然是不足够的。为了阐明这一点,假设每个内存模块均有多个

端口,每个端口均可以向一个处理器(I/O通道)提供服务。令"a"和"b"分别存储在独立的内存模块,

并考察按以下顺序发生的事件。

1) process 1 发送"a :=1"请求到与"a"对应的内存模块1的端口,而内存模块1此时正忙于执行其

它处理器(I/O通道)的操作;

2) process 1 发送取"b"值的请求到与"b"对应的内存模块2的端口,内存模块2此时是空闲,开始

执行该操作。

3) process 2 发送"b :=1"请求到内存模块2,该请求会在process
1发送的取"b"值请求完成之后

再执行;

4) process 2 发送取"a"值的请求到与"a"对应的内存模块1的端口,内存模块1此时仍然处于忙碌。

现在有2个操作等待内存模块1来执行,如果process
2的取"a"值请求先执行,那么两个进程均能同

时进入临界区,导致互斥访问协议失败。如果内存模块采用的是轮询调度算法来响应端口上的请求,那么

这种情况是可能出现的。

在这种情形下,只要两个发往内存模块1的请求不是按照它们被接收到的顺序执行,就会产生错误。

这就要求满足以下的约束条件。

约束条件2:所有处理器发往某一个独立内存模块的内存请求需要按照FIFO队列的方式响应,

发起内存请求等同于向队列中投递请求。

约束条件1暗含一个处理器在当前发起的请求进入队列之前可能不会再发起任何的内存请求。因此,

当队列满时,处理器必须等待。如果两个或更多的进程试图同时向队列投递请求,那么以哪种顺序响应

这些请求就无关紧要了。

注意:如果一个取数据请求所访问的内存位置和队列中的一个写请求所访问的内存位置相同,那么

取请求就不必进入队列,可以简单的返回在该取请求之前已进入队列中的最后一个写入此内存位置的数据。

约束条件1和2确保如果独立的处理器是顺序化的,那么整个多处理器计算机就是顺序一致性的。为了

说明这一点,引入内存请求之间的一个关系描述"->"。定义
A->B,当前仅当:1)请求A和B由同一处理器发

出,且A先于B;或者2)请求A和B发往相同的内存模块,且A先于B进入队列(即A会在B之前执行)。很容易

发现约束条件1和2表明"->"是内存请求集合上的偏序关系。利用各个处理器的顺序性,容易证明:每个存、

取请求会存、取到一样的value(译者:这里指的应该是特定的一个内存请求在多个可能的执行顺序中执行

时访问到的value是一样的),只要所有的操作以任一顺序化的顺序执行,这使得A->B暗含A在B之前执行。

这反过来能证明多处理器计算机的顺序一致性。

约束条件2表明内存模块必须以FIFO的顺序响应请求队列中的请求;这暗含如果队首是存请求且还未

接收到待存入的数据,那么此时内存模块必须保持空闲。可以弱化条件2,以便在这种情形下,内存模块

可以响应其它的请求,只需要保证所有发往同一个内存单元的内存请求按照它们在队列中出现的先后顺序

执行,发往不同内存单元的请求可能会以乱序的方式执行。顺序一致性被禁用,因为这种服务策略在逻辑

上等同于认为每个内存单元均是一个有着请求队列的独立内存模块。(事实上,这些模块可能共享着一些

硬件,这些硬件影响着它们响应访存请求的速度和请求队列的容量,但是这并不影响顺序一致性的逻辑属性。)

这些保证顺序一致性的必须条件排除了一些可以用于加速独立的顺序处理器的技术。对于一些应用程

序而言,以降低处理器速度作为代价来达到顺序一致性可能并不划算。在这种情况下,必须意识到并不能

依赖传统的用于设计多进程算法的方法去正确的执行程序。必须在机器指令的最底层实现处理器同步协议,

验证这些协议的正确性将是一个里程碑式的工作。

参考文献:

[1] E. W. Dijkstra, "Hierarchical ordering of sequential processes," Acta Informatica,

vol. 1, pp. 115-138, 1971.

[2] L. Lamport, "Proving the correctness of multiprocess programs," IEEE Trans.

Software Eng., vol. SE-3, pp. 125-143, Mar. 1977.

[3] S. Owicki and D. Gries, 'Verifying properties of parallel programs: an axiomatic

approach," Commun. Assoc. Comput. Mach., vol. 19, pp. 279-285, May 1976.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: