synchronizes-with
两个线程A,B, 以及一个支持原子操作的变量X,如果A线程对X store了一个新的值,B线程在X上读到了新的值,那就可以说A的store synchronize-with
B 的 load
happens-before
如果一个操作B能看到之前操作A产生的结果,那么A就是happens-before B, 例如在一个线程中,操作A的语句在B之前执行,那么A happens-before
B
Relaxed ordering
保证原子操作,在同一个线程中,对同一个变量的操作满足happens-before, 但跨线程操作中,不能保证顺序
fn write_x_then_y() {
X.store(true, Ordering::Relaxed);
Y.store(true, Ordering::Relaxed);
}
fn read_y_then_x() {
while !Y.load(Ordering::Relaxed) {}
if X.load(Ordering::Relaxed){
Z.fetch_add(1, Ordering::SeqCst);
}
}
fn main() {
let t1 = thread::spawn(move || {
write_x_then_y();
});
let t2 = thread::spawn(move || {
read_y_then_x();
});
t1.join().unwrap();
t2.join().unwrap();
assert_ne!(Z.load(Ordering::SeqCst), 0);
}
write_x_then_y 中,Y store happens-before X store, 但是由于Relax 并不保证sync-with,所以load可能看到的是乱序的store
Acquire-Release ordering
release
release updates we’ve made to memory, “publish” to other threads.
acquire
acquire memory published by other threads, making it avaliable to us.
- threadA store a,b 两个variable,这个时候都保存在A线程的内存中,对于其他线程都不可见
- threadA release store c, 将c publish到主内存中,同时a,b两个变量也同步到了主内存
- threadB, acquire load c,将c从主内存中,同步到B线程中,同时将a,b两个变量也同步到了 threadB
Acquire和release 成对使用,当store使用Release ordering后,后续的Acquire ordering的load操作,都会看到之前的store值,他是sync-with
fn write_x_then_y() {
X.store(true, Ordering::Relaxed);
Y.store(true, Ordering::Release);
}
fn read_y_then_x() {
while !Y.load(Ordering::Acquire){}
if X.load(Ordering::Relaxed) {
Z.fetch_add(1, Ordering::SeqCst);
}
}
fn main() {
let t1 = thread::spawn(move || {
write_x_then_y();
});
let t2 = thread::spawn(move || {
read_y_then_x();
});
t1.join().unwrap();
t2.join().unwrap();
assert_ne!(Z.load(Ordering::SeqCst), 0);
}
Y.load(Ordering::Acquire) Y.store(true, Ordering::Release); 表明线程t1, t2对于Y是syn-with的,并且由于happened-before, X store 保证在Y store之前,X load保证在Y load之后,所以X load X store 虽然是relaxed, 但也保证了顺序
AcqRel
is used to reads the value but also wirtes the value, like fetch_and _add, usually used in doing a single modifation operation
Sequence ordering
保证所有线程会看到完全一致的原子操作顺序