Lamport's Logical Clocks
為了同步logical clocks,Lamport 定義了一個關系叫做happens-before.記作 ->
a->b意味着所有的進程都agree事件a發生在事件b之前。
在兩種情況下,可以很容易的得到這個關系:
1 如果事件a和事件b是同一個進程中的並且事件a發生在事件b前面,那么a->b
2 如果進程A發送一條消息m給進程B,a代表進程A發送消息m的事件,b代表進程B接收消息m的事件,那么a->b(由於消息的傳遞需要時間)
happens-before 關系滿足傳遞性:即(a->b && b->c)->(a->c)
如果事件a和事件b發生在不同的進程,並且這兩個進程沒有傳遞消息,那么既不能推到a->b也不能推到b->a,這樣的兩個事件叫做並發事件
現在需要定義一個事件的函數C,使得[a->b]->[C(a)<C(b)],並且由於是作為一種對時間的衡量,所以C也必須是只增不減的。
Lamport 算法

三個機器上各自跑着一個進程,分別為P1,P2,P3,由於不同的機器上的quartz crystal不一樣,所以不同的機器上的時鍾速率可能是不同的,例如當P1所在
的機器tick了6次,P2所在的機器tick了8次。
圖中,P1給P2發送了消息m1,m1上附帶了發送m1時的時鍾6,隨后P2收到了m1,根據P2接收到m1時的時鍾,認為傳輸消息花了16-6=10個tick
隨后,P3給P2發送消息m3,m3附帶的發送時鍾是60,由於P2的時鍾走的比P3的慢,所以接收到m3時,本機的時鍾56比發送時鍾60小。這是不合理的,需要調整時鍾,
如圖中,將P2的56調整為61,即m3的發送時鍾加1
Lamport logical clocks的實現:
每個進程Pi維護一個本地計數器Ci,相當於logical clocks,按照以下的規則更新Ci
1 每次執行一個事件(例如通過網絡發送消息,或者將消息交給應用層,或者其它的一些內部事件)之前,將Ci加1
2 當Pi發送消息m給Pj的時候,在消息m上附着上Ci
3 當接收進程Pj接收到Pi的發送的消息時,更新自己的Cj = max{Cj,Ci}
Vector Clocks
Lamport logical clocks可以保證(a->b)->( C(a)<C(b) ),但是不能保證( C(a)<C(b) )->(a->b)
也就是說,Lamport logical clocks的問題是:事件a和事件b實際發生的先后順序不能僅僅通過比較C(a)和C(b)來決定。
這是因為Lamport logical clocks沒有capture causality(因果關系),而causality可以通過Vector Clocks來capture,用VC(a)來表示事件a的Vector Clock,
有如下性質:VC(a) < VC(b)可以推出事件a causally 發生在事件b之前(也就是事件a發生在事件b之前)
為每個進程Pi維護一個向量VC,也就是Pi的Vector Clock,這個向量VC有如下屬性:
1 VCi[i] 是到目前為止進程Pi上發生的事件的個數
2 VCi[k] 是進程Pi知道的進程Pk發生的事件的個數(即Pi對Pj的知識)
每個進程的VC可以通過以下規則進行維護(和Lamport logical clocks算法類似):
1 進程Pi每次執行一個事件之前,將VCi[i]加1
2 當Pi發送消息m給Pj的時候,在消息m上附着上VCi(進程Pi的向量時鍾)
3 當接收進程Pj接收到Pi的發送的消息時,更新自己的VCj[k] = max{VCj[k],VCi[k]} ,對於所有的k
causally-ordered multicasting
一個進程組中,每個進程需要廣播消息給其它進程(相當於一個並發更新問題),一個消息被delivered到應用層,僅當所有的causally發生之前的消息都被收到
假設:Pi給Pj發送消息m,那么Pj可以將消息m交給應用層必須首先滿足上面兩個條件:
1 VCj[i] = VCi[i] - 1
2 VCi[k] <= VCj[k] for all k≠i
第一個條件的意思是指Pj看到了Pi發生的所有的事件(不包括本次發送消息m的時間)
第二個條件意味着,Pj看到了其它的所有的進程看到的事件。
以上兩個條件說明,對消息m做下一步動作(比如本例中的將消息m交給應用層)之前,所有的m依賴的消息都收到了。
例子:

首先P0給P1和P2廣播消息m,P1很快收到了消息m,然后P1馬上給P0和P2廣播消息m*,P2也很快收到了消息m*,但是不能將m* delivered給應用程序,
因為VC1[0] > VC2[0](違反了條件2,因為P2還沒有收到P0廣播的消息m),隨后在P2收到了m后,兩個條件都滿足了,就可以把消息delivered給應用層了。
