-
-
Save grahamking/415b487f754de048ecd34a6c841012df 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 std::{ | |
| sync::atomic::{AtomicPtr, Ordering}, | |
| time::Duration, | |
| }; | |
| const ONE_MS: Duration = Duration::from_millis(1); | |
| const LOOPS: usize = 1000; | |
| const ORDERING: Ordering = Ordering::Relaxed; | |
| struct User { | |
| name: String, | |
| permissions: u64, | |
| } | |
| impl User { | |
| fn make(i: usize) -> Box<Self> { | |
| Box::new(Self { | |
| name: format!("name_{i}"), | |
| permissions: i as u64, | |
| }) | |
| } | |
| } | |
| fn main() { | |
| let on_call_ptr = AtomicPtr::new(Box::into_raw(User::make(0))); | |
| // The scope avoids needing an `Arc` | |
| std::thread::scope(|s| { | |
| // Writer | |
| s.spawn(|| writer(&on_call_ptr)); | |
| // Readers | |
| for thread_idx in 0..3 { | |
| let on_call_ptr = &on_call_ptr; | |
| s.spawn(move || reader(thread_idx, on_call_ptr)); | |
| } | |
| }); | |
| std::thread::sleep(ONE_MS * (LOOPS as u32 + 100)); | |
| } | |
| /// Change who is on call, occasionally, from a single thread. | |
| #[inline(never)] | |
| fn writer(on_call_ptr: &AtomicPtr<User>) { | |
| for user_id in 1..(LOOPS / 10) { | |
| std::thread::sleep(ONE_MS * 10); | |
| let user_ptr = Box::into_raw(User::make(user_id)); | |
| // Atomically set the next user as on-call | |
| let old = on_call_ptr.swap(user_ptr, ORDERING); | |
| println!("--- goes on call: {user_id}"); | |
| // De-allocate previous user | |
| unsafe { drop(Box::from_raw(old)) }; | |
| } | |
| } | |
| /// Read who is on call, often and from many threads. | |
| #[inline(never)] | |
| fn reader(id: usize, on_call_ptr: &AtomicPtr<User>) { | |
| for l in 0..LOOPS { | |
| // Only the readers access the internals of User, hence it is safe. | |
| let on_call = unsafe { &*on_call_ptr.load(ORDERING) }; | |
| if id == 0 && l % 10 == 0 { | |
| println!("thread {id}: {} {}", on_call.name, on_call.permissions); | |
| } | |
| std::thread::sleep(ONE_MS); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment