Skip to content

Instantly share code, notes, and snippets.

@azyobuzin
Created September 23, 2025 15:04
Show Gist options
  • Select an option

  • Save azyobuzin/028d2f94d10a9e050ee75ae4f52149ba to your computer and use it in GitHub Desktop.

Select an option

Save azyobuzin/028d2f94d10a9e050ee75ae4f52149ba to your computer and use it in GitHub Desktop.
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