Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use std::mem;
- use std::sync::Arc;
- use std::sync::atomic::{Ordering, AtomicPtr};
- /// Synchronized data structure which allows for lock-free reads of enclosed data.
- pub struct FreeReader<T> {
- ptr: AtomicPtr<T>,
- }
- impl<T> FreeReader<T> {
- pub fn new(data: T) -> FreeReader<T> {
- let data = Arc::new(data);
- let ptr = Arc::into_raw(data);
- let ptr = AtomicPtr::new(ptr as *mut T);
- FreeReader {
- ptr
- }
- }
- pub fn read(&self) -> Arc<T> {
- let ptr = self.ptr.load(Ordering::Relaxed);
- let data = unsafe { Arc::from_raw(ptr as *const T) };
- let ret = data.clone();
- // forget the original Arc so we don't drop its reference count
- mem::forget(data);
- ret
- }
- pub fn store(&self, new_data: T) {
- let new_data = Arc::new(new_data);
- let new_ptr = Arc::into_raw(new_data);
- let ptr = self.ptr.swap(new_ptr as *mut T, Ordering::AcqRel);
- // drop the old data to drop its reference count
- unsafe { Arc::from_raw(ptr as *const T) };
- }
- pub fn compare_and_store(&self, mut new_data: impl FnMut(Arc<T>) -> T) {
- let mut old_ptr = self.ptr.load(Ordering::Acquire);
- loop {
- let old_data = unsafe { Arc::from_raw(old_ptr as *const T) };
- let data = new_data(old_data);
- let new_ptr = Arc::into_raw(Arc::new(data)) as *mut T;
- let new_ptr = self.ptr.compare_and_swap(old_ptr, new_ptr, Ordering::AcqRel);
- if new_ptr == old_ptr {
- break;
- } else {
- old_ptr = new_ptr;
- }
- }
- }
- }
- impl<T> Drop for FreeReader<T> {
- fn drop(&mut self) {
- let ptr = self.ptr.load(Ordering::SeqCst);
- // drop the old data to drop its reference count
- unsafe { Arc::from_raw(ptr as *const T) };
- }
- }
- fn main() {
- use std::thread;
- use std::sync::Barrier;
- let mut threads = vec![];
- let data = Arc::new(FreeReader::new(5usize));
- let artificial_wait = Arc::new(Barrier::new(5));
- for _ in 0..10 {
- let reader = data.clone();
- let artificial_wait = artificial_wait.clone();
- threads.push(thread::spawn(move || {
- artificial_wait.wait();
- reader.compare_and_store(|old_value| {
- println!("old_value: {}", *old_value);
- *old_value + 1
- });
- }));
- }
- for t in threads {
- t.join().unwrap();
- }
- println!("\nnew value: {}", *data.read());
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement