在 gdb 下達 disassemble /m <function name>
進行反組譯
critical section 的解決要件:
適用長度:
atomic_thread_fence()
可防止指令重排的越界
x86 instructions :
lfence
fence for loadsfence
fence for storesun solaris 依持鎖人當下的情況來判定
glibc 根據之前 lock 等待的時間,決定 spinlock 的 loop 次數
man futex
glibc 沒有對此 system call 的包裝,需要直接使用 syscall()
TODO
看 jserv 版本的解說交互參照
single producer single cosumer problem
an example solution
constrain:
pthread 有提供 read write lock 供同時讀寫用
pthread_rwlock_wrlock()
deadlock
可能違反 bounded waiting
可能造成效能瓶頸
每次使用 semaphore 都會進入 kernel mode,因此過多的 semaphore 會對系統帶來效能負擔。
block
目前的 CPU 通常是混用兩種方法
cache coherent 不保證 atomic operation
傳統上有 instruction: test_n_set
和 swap
test_n_set
相當於 C 程式碼:
使用範例:
C11 有 atomic_exchange()
類似於 test_n_set
swap
相當於 C 程式碼:
此二方法一直更新記憶體,表示一直觸發 cache coherence,造成效率負擔。
因此以 compare exchange 來改善,compare exchange 只會讀取值做比較,通常不需要額外 cache coherence。
expected
是 local variable 不需要做 coherent
使用範例:
RISC 系列常使用 load-link (LL) 或 store-condition (SC) 實現
檢查 - 進入會出錯,因為中間的過程可能導致很多 thread 都進到 critical section。正確的方法是改變狀態 - 檢查 - 確認是否成功 lock,或是使用 atomic 方式檢查 - 進入 (上鎖)。
Use atomic_int
rather than volatile int
.
The volatile types do not provide inter-thread synchronization, memory ordering, or atomicity.
https://en.cppreference.com/w/c/language/atomic
FIFO
有一個最大門票數值 ,writer 每次要拿到 張票才能進入, reader 只需要 張票就能進入。
busy waiting 可以改用 inline assembly asm("pause")
來省電
C11 memory order
e.g.
seq_cst 等同在硬體上一個大鎖,大幅影響多核效能