Created
September 23, 2025 15:04
-
-
Save azyobuzin/028d2f94d10a9e050ee75ae4f52149ba to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| use loom::cell::UnsafeCell; | |
| use loom::sync::Arc; | |
| use loom::sync::atomic::{AtomicBool, Ordering}; | |
| use loom::thread; | |
| struct Shared { | |
| data: UnsafeCell<u32>, // 非原子データ(ロック/フラグで保護する前提) | |
| ready: AtomicBool, | |
| } | |
| // UnsafeCell の並行アクセスは本来未定義だが、今回は可視性バグの再現用に intentionally 行っている。 | |
| unsafe impl Send for Shared {} | |
| unsafe impl Sync for Shared {} | |
| /// ---- Relaxed: 壊れることを再現 ---- | |
| #[test] | |
| #[should_panic(expected = "Causality violation: Concurrent read and write accesses.")] | |
| fn message_passing_relaxed_breaks() { | |
| loom::model(|| { | |
| let shared = Arc::new(Shared { | |
| data: UnsafeCell::new(0), | |
| ready: AtomicBool::new(false), | |
| }); | |
| // Writer: data=1 -> ready=true(Relaxed) | |
| let s1 = shared.clone(); | |
| let t1 = thread::spawn(move || { | |
| s1.data.with_mut(|p| unsafe { *p = 1 }); | |
| // 公開のための Release を付けない | |
| s1.ready.store(true, Ordering::Relaxed); | |
| }); | |
| // Reader: ready を見てから data を読む | |
| let s2 = shared.clone(); | |
| let t2 = thread::spawn(move || { | |
| // 1 回だけ確認。true なら読む。 | |
| if s2.ready.load(Ordering::Relaxed) { | |
| // ちょっとだけスケジューリングの自由度を与える | |
| thread::yield_now(); | |
| let v = s2.data.with(|p| unsafe { *p }); | |
| // Acquire/Release なら 1 が必ず見えるはずだが、 | |
| // Relaxed だと loom が探索する実行の中に v==0 がありうる。 | |
| assert_eq!( | |
| v, 1, | |
| "Relaxed allowed ready==true but stale data (v=={})", | |
| v | |
| ); | |
| } | |
| }); | |
| t1.join().unwrap(); | |
| t2.join().unwrap(); | |
| }); | |
| } | |
| /// ---- Acquire/Release: 常に正しくなる ---- | |
| #[test] | |
| fn message_passing_acqrel_ok() { | |
| loom::model(|| { | |
| let shared = Arc::new(Shared { | |
| data: UnsafeCell::new(0), | |
| ready: AtomicBool::new(false), | |
| }); | |
| let s1 = shared.clone(); | |
| let t1 = thread::spawn(move || { | |
| s1.data.with_mut(|p| unsafe { *p = 1 }); | |
| // 書き込みを公開 | |
| s1.ready.store(true, Ordering::Release); | |
| }); | |
| let s2 = shared.clone(); | |
| let t2 = thread::spawn(move || { | |
| if s2.ready.load(Ordering::Acquire) { | |
| thread::yield_now(); | |
| let v = s2.data.with(|p| unsafe { *p }); | |
| assert_eq!(v, 1); | |
| } | |
| }); | |
| t1.join().unwrap(); | |
| t2.join().unwrap(); | |
| }); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment