# Experiments on Concurrency - Happens-before
contributed by < [`jeffrey.w`](https://github.com/jeffrey-minwei/experiments-on-concurrency/tree/master/c11-standard) >
## Introduction
C 語言在 C99 的時候還沒有將並行 (`concurrency`) 納入到語言的標準,但到了[`C11 standard`](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) 就開始將並行、`memory order` 相關的機制加入到規格裡,本文將透過學習 [`C11 standard`](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) 和 [`C++11 standard`](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3376.pdf) 來理解並行在語言層面的機制,然後使用 `C11` 來實驗並行。
## Modification order
§5.1.2.4/7 定義了 `modification order`
> All modifications to a particular atomic object M occur in some particular total order, called the modification order of M. If A and B are modifications of an atomic object M, and A happens before B, then A shall precede B in the modification order of M...
§5.1.2.4/7 提到兩件事:
1. particular total order
2. 假設 A 和 B 代表對 atomic object M 的 modification ,然後 A happens before B ${\Rightarrow}$ 對於 M 的 modification order,**A 會先於 B**
### Total order
§5.1.2.4/7 所說的 `particular total order` 是指什麼?
> All modifications to a particular atomic object M occur in some **particular total order**
數學上的 `total order` 是指一個集合裡的 `binary relation` [[`1`](https://en.wikipedia.org/wiki/Total_order)],這個二元關係具有三個特性:反對稱、遞移和 `Connexity`:
- 反對稱 ([antisymmetric](https://en.wikipedia.org/wiki/Antisymmetric_relation))
- ${\displaystyle \forall a, b\in X, \ aRb \ and \ bRa\;\Rightarrow \;a=b}$
- 遞移 ([transitive](https://en.wikipedia.org/wiki/Transitive_relation))
- ${\displaystyle \forall a,b,c\in X,\ aRb\ and \ bRc\;\Rightarrow aRc}$
- [Connexity](https://en.wikipedia.org/wiki/Connex_relation)
- ${\displaystyle \forall a, b\in X, \ \displaystyle aRb}$ or ${\displaystyle bRa}$
這三個特性如果從 modification order 的角度來看會是怎樣?
假設 A, B, C 各自代表**一個 atomic object 的 modification**,底下就可以用 `binary relation` ${R}$ 來表示 **happens-before relation**
- ${\displaystyle \forall A, B, C\in X}$
- ${\ R(A, B)}$ and${\ R(B, A)}$ ${\Rightarrow \;A=B}$.
- ${\ R(A, B)}$ and${\ R(B, C)}$ ${\Rightarrow \ R(A, C)}$
- ${\ R(A, B)}$ or${\ R(B, A)}$
回到 §5.1.2.4/7 所說的 `particular total order`,假設其中一種 `total order` 如下圖所示:
```graphviz
digraph G{
A -> B -> C;
}
```
:::warning
上圖只是 `total order`,還沒有提到 `modification order`
:::
初始條件:
- `binary relation` ${R}$ 表示 **happens-before relation**
- ${\displaystyle A, B, C\in X}$
- ${\displaystyle (A, B), (B, C), (A, C)\in R}$
我們一條一條來檢視一下這幾個 `modification` 的順序符不符合 `total order` 的定義
- ${(A, B)}$, ${(B, A) \in R}$ ${\Rightarrow \ A=B}$
- ${(B, A) \notin R}$, ${(C, B) \notin R}$, ${(C, A) \notin R}$
- ${(A, B)}$, ${(B, C) \in R}$ ${\Rightarrow \ (A, C) \in R}$
- trivial
- ${(A, B) \in R}$ or ${(B, A) \in R}$
- ${(A, B) \in R \Rightarrow (A, B) \notin R}$
- ${(B, C) \in R \Rightarrow (C, B) \notin R}$
- ${(A, C) \in R \Rightarrow (C, A) \notin R}$
至此,我們知道了 ${A, B, C}$ 這三個 `modification` 的 `happens-before relation` 符合 `total order` 的定義。
所以 ${A, B, C}$ 的 `modification order` 符合規格書的順序就會是 ${A \rightarrow B \rightarrow C}$。
### Example
寫一段 code 來實驗 `modification order`,底下的範例改寫自 [`Preshing on Programming, Memory Ordering at Compile Time`](https://preshing.com/20120625/memory-ordering-at-compile-time/)
```clike
#include <stdatomic.h>
atomic_int a = ATOMIC_VAR_INIT(0);
atomic_int b = ATOMIC_VAR_INIT(0);
int c, d;
void test_atomic() {
atomic_fetch_add(&b, 5);
atomic_store(&a, b);
b = ATOMIC_VAR_INIT(42);
}
void test(){
c = d + 5;
d = 42;
}
int main(int argc, char **argv) {
test();
test_atomic();
return 0;
}
```
先看 `test` 的組合語言在 `gcc -O2 -S -masm=intel` 和 `gcc -S -masm=intel` 的差別
**gcc -O2 -S -masm=intel**
```
test:
...
mov eax, DWORD PTR d[rip]
mov DWORD PTR d[rip], 42
add eax, 5
...
```
**沒有最佳化** `gcc -S -masm=intel`
```
test:
...
add eax, 5
mov DWORD PTR c[rip], eax
mov DWORD PTR d[rip], 42
...
```
再使用 `gcc -O2 -S -masm=intel`,從組合語言來比較 `test` 和 `test_atomic`
```
test_atomic:
...
lock add DWORD PTR b[rip], 5
mov eax, DWORD PTR b[rip]
mov DWORD PTR a[rip], eax
mfence
mov DWORD PTR b[rip], 42
...
```
```
test:
...
mov eax, DWORD PTR d[rip]
mov DWORD PTR d[rip], 42
add eax, 5
...
```
我們從幾個角度來看上述幾種結果在 [`C11 規格`](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) 的意義:
- test 在 -O2 的 assembly 有沒有違反 `happens-before`?
- test_atomic 在 -O2 的 assembly 有沒有符合 `modification order`?
- [`C11 規格`](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf)<sub>(§5.1.2.4/7)</sub> 對 `modification order` 的定義
> If A and B are modifications of an atomic object M, and A happens before B, then A shall precede B in the modification order of M...
- 假設 $A$ 和 $B$ 是對 `atomic object` 的 `modification`
- $A$ `happens before` $B$ ${\Rightarrow}$ $A$ 的 `modification order` 在 $B$ 的前面
- 所以,加了 `-O2` 仍然符合 `modification order`
參考維基百科對 [全序關係](https://zh.wikipedia.org/wiki/%E5%85%A8%E5%BA%8F%E5%85%B3%E7%B3%BB) 的說明,我們知道全序關係是一個二元關係,全序集是指一個**滿足全序關係的集合**,在全序集裡,元素任意一對都是可以比較的。
至此,重新再看一次 [`C11 規格, §5.1.2.4/7`](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) 所定義的 `modification order`
> All modifications to a particular atomic object M occur in some particular total order, called the modification order of M. If A and B are modifications of an atomic object M, and A happens before B, then A shall precede B in the modification order of M...
- 有一個全序集,裡面的元素都是**對 atomic object 的 modification**,這個全序集上的二元關係就是 `happens before`。
- 因為**任意一對**元素都是可以比較的,所以,任意兩個 `modification` $A$, $B$,比較的結果可以是 $A$ `happens before` $B$ 也可以是 $B$ `happens before` $A$。
- 如果 $A$ `happens before` $B$ 而且 $B$ `happens before` $A$ $\Rightarrow$ $A$ = $B$
- 如果 $A$ `happens before` $B$ $\Rightarrow$ $A$ 的 `modification order` 會在 $B$ 之前。
## Happens before
## References
- [ ] [並行程式設計](https://hackmd.io/@sysprog/concurrency)
- [ ] [Preshing on Programming, Memory Ordering at Compile Time, JUN 25, 2012](https://preshing.com/20120625/memory-ordering-at-compile-time/)
- [ ] [Concurrency系列(二): 從Sequenced-Before開始說起](http://opass.logdown.com/posts/788206-concurrency-series-2-starting-from-sequenced-before)
###### tags: `concurrency` `c11` `c++11` `happens-before`