pub struct AtomicRef<T> { /* private fields */ }Expand description
Atomic reference type.
Provides easy-to-use atomic operations on references with automatic memory
ordering selection. Uses Arc<T> for thread-safe reference counting.
§Memory Ordering Strategy
This type uses the same memory ordering strategy as other atomic types:
-
Read operations (
load): UseAcquireordering to ensure that all writes from other threads that happened before aReleasestore are visible after this load. -
Write operations (
store): UseReleaseordering to ensure that all prior writes in this thread are visible to other threads that perform anAcquireload. -
Read-Modify-Write operations (
swap,compare_set): UseAcqRelordering to combine bothAcquireandReleasesemantics. -
CAS failure: Use
Acquireordering on failure to observe the actual value written by another thread.
§Implementation Details
This type stores an Arc<T> as a raw pointer in AtomicPtr<T>. All
operations properly manage reference counts to prevent memory leaks or
use-after-free errors.
§Features
- Automatic memory ordering selection
- Thread-safe reference counting via
Arc - Functional update operations
- Zero-cost abstraction with inline methods
§Example
use prism3_rust_concurrent::atomic::AtomicRef;
use std::sync::Arc;
#[derive(Debug, Clone)]
struct Config {
timeout: u64,
max_retries: u32,
}
let config = Arc::new(Config {
timeout: 1000,
max_retries: 3,
});
let atomic_config = AtomicRef::new(config);
// Update configuration
let new_config = Arc::new(Config {
timeout: 2000,
max_retries: 5,
});
let old_config = atomic_config.swap(new_config);
assert_eq!(old_config.timeout, 1000);
assert_eq!(atomic_config.load().timeout, 2000);§Author
Haixing Hu
Implementations§
Source§impl<T> AtomicRef<T>
impl<T> AtomicRef<T>
Sourcepub fn new(value: Arc<T>) -> Self
pub fn new(value: Arc<T>) -> Self
Creates a new atomic reference.
§Parameters
value- The initial reference.
§Example
use prism3_rust_concurrent::atomic::AtomicRef;
use std::sync::Arc;
let data = Arc::new(42);
let atomic = AtomicRef::new(data);
assert_eq!(*atomic.load(), 42);Examples found in repository?
24fn main() {
25 println!("=== Atomic Reference Example ===\n");
26
27 // Example 1: Basic reference operations
28 println!("1. Basic Reference Operations:");
29 let config = Arc::new(Config {
30 version: 1,
31 name: "initial".to_string(),
32 value: 100,
33 });
34 let atomic_config = AtomicRef::new(config.clone());
35
36 println!(" Initial config: {:?}", atomic_config.load());
37
38 let new_config = Arc::new(Config {
39 version: 2,
40 name: "updated".to_string(),
41 value: 200,
42 });
43 atomic_config.store(new_config);
44
45 println!(" Updated config: {:?}", atomic_config.load());
46
47 // Example 2: Compare-and-swap
48 println!("\n2. Compare-and-Swap:");
49 let config = Arc::new(Config {
50 version: 1,
51 name: "v1".to_string(),
52 value: 10,
53 });
54 let atomic_config = AtomicRef::new(config.clone());
55
56 let current = atomic_config.load();
57 let new_config = Arc::new(Config {
58 version: 2,
59 name: "v2".to_string(),
60 value: 20,
61 });
62
63 match atomic_config.compare_set(¤t, new_config) {
64 Ok(_) => println!(" CAS succeeded: {:?}", atomic_config.load()),
65 Err(actual) => println!(" CAS failed: {:?}", actual),
66 }
67
68 // Example 3: Functional updates
69 println!("\n3. Functional Updates:");
70 let config = Arc::new(Config {
71 version: 1,
72 name: "counter".to_string(),
73 value: 0,
74 });
75 let atomic_config = AtomicRef::new(config);
76
77 let old = atomic_config.fetch_update(|current| {
78 Arc::new(Config {
79 version: current.version + 1,
80 name: current.name.clone(),
81 value: current.value + 10,
82 })
83 });
84
85 println!(" Old config: {:?}", old);
86 println!(" New config: {:?}", atomic_config.load());
87
88 // Example 4: Multi-threaded updates
89 println!("\n4. Multi-threaded Updates:");
90 let config = Arc::new(Config {
91 version: 0,
92 name: "shared".to_string(),
93 value: 0,
94 });
95 let atomic_config = Arc::new(AtomicRef::new(config));
96 let mut handles = vec![];
97
98 for i in 0..10 {
99 let atomic_config = atomic_config.clone();
100 let handle = thread::spawn(move || {
101 for _ in 0..10 {
102 atomic_config.fetch_update(|current| {
103 Arc::new(Config {
104 version: current.version + 1,
105 name: current.name.clone(),
106 value: current.value + 1,
107 })
108 });
109 }
110 println!(" Thread {} completed", i);
111 });
112 handles.push(handle);
113 }
114
115 for handle in handles {
116 handle.join().unwrap();
117 }
118
119 let final_config = atomic_config.load();
120 println!(" Final config: {:?}", final_config);
121 println!(" Expected version: 100, actual: {}", final_config.version);
122 println!(" Expected value: 100, actual: {}", final_config.value);
123
124 println!("\n=== Example completed ===");
125}Sourcepub fn load(&self) -> Arc<T>
pub fn load(&self) -> Arc<T>
Gets the current reference.
§Memory Ordering
Uses Acquire ordering. This ensures that all writes from other
threads that happened before a Release store are visible after
this load.
§Returns
A cloned Arc pointing to the current value.
§Example
use prism3_rust_concurrent::atomic::AtomicRef;
use std::sync::Arc;
let atomic = AtomicRef::new(Arc::new(42));
let value = atomic.load();
assert_eq!(*value, 42);Examples found in repository?
24fn main() {
25 println!("=== Atomic Reference Example ===\n");
26
27 // Example 1: Basic reference operations
28 println!("1. Basic Reference Operations:");
29 let config = Arc::new(Config {
30 version: 1,
31 name: "initial".to_string(),
32 value: 100,
33 });
34 let atomic_config = AtomicRef::new(config.clone());
35
36 println!(" Initial config: {:?}", atomic_config.load());
37
38 let new_config = Arc::new(Config {
39 version: 2,
40 name: "updated".to_string(),
41 value: 200,
42 });
43 atomic_config.store(new_config);
44
45 println!(" Updated config: {:?}", atomic_config.load());
46
47 // Example 2: Compare-and-swap
48 println!("\n2. Compare-and-Swap:");
49 let config = Arc::new(Config {
50 version: 1,
51 name: "v1".to_string(),
52 value: 10,
53 });
54 let atomic_config = AtomicRef::new(config.clone());
55
56 let current = atomic_config.load();
57 let new_config = Arc::new(Config {
58 version: 2,
59 name: "v2".to_string(),
60 value: 20,
61 });
62
63 match atomic_config.compare_set(¤t, new_config) {
64 Ok(_) => println!(" CAS succeeded: {:?}", atomic_config.load()),
65 Err(actual) => println!(" CAS failed: {:?}", actual),
66 }
67
68 // Example 3: Functional updates
69 println!("\n3. Functional Updates:");
70 let config = Arc::new(Config {
71 version: 1,
72 name: "counter".to_string(),
73 value: 0,
74 });
75 let atomic_config = AtomicRef::new(config);
76
77 let old = atomic_config.fetch_update(|current| {
78 Arc::new(Config {
79 version: current.version + 1,
80 name: current.name.clone(),
81 value: current.value + 10,
82 })
83 });
84
85 println!(" Old config: {:?}", old);
86 println!(" New config: {:?}", atomic_config.load());
87
88 // Example 4: Multi-threaded updates
89 println!("\n4. Multi-threaded Updates:");
90 let config = Arc::new(Config {
91 version: 0,
92 name: "shared".to_string(),
93 value: 0,
94 });
95 let atomic_config = Arc::new(AtomicRef::new(config));
96 let mut handles = vec![];
97
98 for i in 0..10 {
99 let atomic_config = atomic_config.clone();
100 let handle = thread::spawn(move || {
101 for _ in 0..10 {
102 atomic_config.fetch_update(|current| {
103 Arc::new(Config {
104 version: current.version + 1,
105 name: current.name.clone(),
106 value: current.value + 1,
107 })
108 });
109 }
110 println!(" Thread {} completed", i);
111 });
112 handles.push(handle);
113 }
114
115 for handle in handles {
116 handle.join().unwrap();
117 }
118
119 let final_config = atomic_config.load();
120 println!(" Final config: {:?}", final_config);
121 println!(" Expected version: 100, actual: {}", final_config.version);
122 println!(" Expected value: 100, actual: {}", final_config.value);
123
124 println!("\n=== Example completed ===");
125}Sourcepub fn store(&self, value: Arc<T>)
pub fn store(&self, value: Arc<T>)
Sets a new reference.
§Memory Ordering
Uses Release ordering. This ensures that all prior writes in this
thread are visible to other threads that perform an Acquire load.
§Parameters
value- The new reference to set.
§Example
use prism3_rust_concurrent::atomic::AtomicRef;
use std::sync::Arc;
let atomic = AtomicRef::new(Arc::new(42));
atomic.store(Arc::new(100));
assert_eq!(*atomic.load(), 100);Examples found in repository?
24fn main() {
25 println!("=== Atomic Reference Example ===\n");
26
27 // Example 1: Basic reference operations
28 println!("1. Basic Reference Operations:");
29 let config = Arc::new(Config {
30 version: 1,
31 name: "initial".to_string(),
32 value: 100,
33 });
34 let atomic_config = AtomicRef::new(config.clone());
35
36 println!(" Initial config: {:?}", atomic_config.load());
37
38 let new_config = Arc::new(Config {
39 version: 2,
40 name: "updated".to_string(),
41 value: 200,
42 });
43 atomic_config.store(new_config);
44
45 println!(" Updated config: {:?}", atomic_config.load());
46
47 // Example 2: Compare-and-swap
48 println!("\n2. Compare-and-Swap:");
49 let config = Arc::new(Config {
50 version: 1,
51 name: "v1".to_string(),
52 value: 10,
53 });
54 let atomic_config = AtomicRef::new(config.clone());
55
56 let current = atomic_config.load();
57 let new_config = Arc::new(Config {
58 version: 2,
59 name: "v2".to_string(),
60 value: 20,
61 });
62
63 match atomic_config.compare_set(¤t, new_config) {
64 Ok(_) => println!(" CAS succeeded: {:?}", atomic_config.load()),
65 Err(actual) => println!(" CAS failed: {:?}", actual),
66 }
67
68 // Example 3: Functional updates
69 println!("\n3. Functional Updates:");
70 let config = Arc::new(Config {
71 version: 1,
72 name: "counter".to_string(),
73 value: 0,
74 });
75 let atomic_config = AtomicRef::new(config);
76
77 let old = atomic_config.fetch_update(|current| {
78 Arc::new(Config {
79 version: current.version + 1,
80 name: current.name.clone(),
81 value: current.value + 10,
82 })
83 });
84
85 println!(" Old config: {:?}", old);
86 println!(" New config: {:?}", atomic_config.load());
87
88 // Example 4: Multi-threaded updates
89 println!("\n4. Multi-threaded Updates:");
90 let config = Arc::new(Config {
91 version: 0,
92 name: "shared".to_string(),
93 value: 0,
94 });
95 let atomic_config = Arc::new(AtomicRef::new(config));
96 let mut handles = vec![];
97
98 for i in 0..10 {
99 let atomic_config = atomic_config.clone();
100 let handle = thread::spawn(move || {
101 for _ in 0..10 {
102 atomic_config.fetch_update(|current| {
103 Arc::new(Config {
104 version: current.version + 1,
105 name: current.name.clone(),
106 value: current.value + 1,
107 })
108 });
109 }
110 println!(" Thread {} completed", i);
111 });
112 handles.push(handle);
113 }
114
115 for handle in handles {
116 handle.join().unwrap();
117 }
118
119 let final_config = atomic_config.load();
120 println!(" Final config: {:?}", final_config);
121 println!(" Expected version: 100, actual: {}", final_config.version);
122 println!(" Expected value: 100, actual: {}", final_config.value);
123
124 println!("\n=== Example completed ===");
125}Sourcepub fn swap(&self, value: Arc<T>) -> Arc<T>
pub fn swap(&self, value: Arc<T>) -> Arc<T>
Swaps the current reference with a new reference, returning the old reference.
§Memory Ordering
Uses AcqRel ordering. This provides full synchronization for this
read-modify-write operation.
§Parameters
value- The new reference to swap in.
§Returns
The old reference.
§Example
use prism3_rust_concurrent::atomic::AtomicRef;
use std::sync::Arc;
let atomic = AtomicRef::new(Arc::new(10));
let old = atomic.swap(Arc::new(20));
assert_eq!(*old, 10);
assert_eq!(*atomic.load(), 20);Sourcepub fn compare_set(&self, current: &Arc<T>, new: Arc<T>) -> Result<(), Arc<T>>
pub fn compare_set(&self, current: &Arc<T>, new: Arc<T>) -> Result<(), Arc<T>>
Compares and sets the reference atomically.
If the current reference equals current (by pointer equality), sets
it to new and returns Ok(()). Otherwise, returns Err(actual)
where actual is the current reference.
§Memory Ordering
- Success: Uses
AcqRelordering to ensure full synchronization when the exchange succeeds. - Failure: Uses
Acquireordering to observe the actual value written by another thread.
§Parameters
current- The expected current reference.new- The new reference to set if current matches.
§Returns
Ok(()) on success, or Err(actual) on failure.
§Note
Comparison uses pointer equality (Arc::ptr_eq), not value equality.
§Example
use prism3_rust_concurrent::atomic::AtomicRef;
use std::sync::Arc;
let atomic = AtomicRef::new(Arc::new(10));
let current = atomic.load();
assert!(atomic.compare_set(¤t, Arc::new(20)).is_ok());
assert_eq!(*atomic.load(), 20);Examples found in repository?
24fn main() {
25 println!("=== Atomic Reference Example ===\n");
26
27 // Example 1: Basic reference operations
28 println!("1. Basic Reference Operations:");
29 let config = Arc::new(Config {
30 version: 1,
31 name: "initial".to_string(),
32 value: 100,
33 });
34 let atomic_config = AtomicRef::new(config.clone());
35
36 println!(" Initial config: {:?}", atomic_config.load());
37
38 let new_config = Arc::new(Config {
39 version: 2,
40 name: "updated".to_string(),
41 value: 200,
42 });
43 atomic_config.store(new_config);
44
45 println!(" Updated config: {:?}", atomic_config.load());
46
47 // Example 2: Compare-and-swap
48 println!("\n2. Compare-and-Swap:");
49 let config = Arc::new(Config {
50 version: 1,
51 name: "v1".to_string(),
52 value: 10,
53 });
54 let atomic_config = AtomicRef::new(config.clone());
55
56 let current = atomic_config.load();
57 let new_config = Arc::new(Config {
58 version: 2,
59 name: "v2".to_string(),
60 value: 20,
61 });
62
63 match atomic_config.compare_set(¤t, new_config) {
64 Ok(_) => println!(" CAS succeeded: {:?}", atomic_config.load()),
65 Err(actual) => println!(" CAS failed: {:?}", actual),
66 }
67
68 // Example 3: Functional updates
69 println!("\n3. Functional Updates:");
70 let config = Arc::new(Config {
71 version: 1,
72 name: "counter".to_string(),
73 value: 0,
74 });
75 let atomic_config = AtomicRef::new(config);
76
77 let old = atomic_config.fetch_update(|current| {
78 Arc::new(Config {
79 version: current.version + 1,
80 name: current.name.clone(),
81 value: current.value + 10,
82 })
83 });
84
85 println!(" Old config: {:?}", old);
86 println!(" New config: {:?}", atomic_config.load());
87
88 // Example 4: Multi-threaded updates
89 println!("\n4. Multi-threaded Updates:");
90 let config = Arc::new(Config {
91 version: 0,
92 name: "shared".to_string(),
93 value: 0,
94 });
95 let atomic_config = Arc::new(AtomicRef::new(config));
96 let mut handles = vec![];
97
98 for i in 0..10 {
99 let atomic_config = atomic_config.clone();
100 let handle = thread::spawn(move || {
101 for _ in 0..10 {
102 atomic_config.fetch_update(|current| {
103 Arc::new(Config {
104 version: current.version + 1,
105 name: current.name.clone(),
106 value: current.value + 1,
107 })
108 });
109 }
110 println!(" Thread {} completed", i);
111 });
112 handles.push(handle);
113 }
114
115 for handle in handles {
116 handle.join().unwrap();
117 }
118
119 let final_config = atomic_config.load();
120 println!(" Final config: {:?}", final_config);
121 println!(" Expected version: 100, actual: {}", final_config.version);
122 println!(" Expected value: 100, actual: {}", final_config.value);
123
124 println!("\n=== Example completed ===");
125}Sourcepub fn compare_set_weak(
&self,
current: &Arc<T>,
new: Arc<T>,
) -> Result<(), Arc<T>>
pub fn compare_set_weak( &self, current: &Arc<T>, new: Arc<T>, ) -> Result<(), Arc<T>>
Weak version of compare-and-set.
May spuriously fail even when the comparison succeeds. Should be used in a loop.
Uses AcqRel ordering on success and Acquire ordering on failure.
§Parameters
current- The expected current reference.new- The new reference to set if current matches.
§Returns
Ok(()) on success, or Err(actual) on failure.
§Example
use prism3_rust_concurrent::atomic::AtomicRef;
use std::sync::Arc;
let atomic = AtomicRef::new(Arc::new(10));
let mut current = atomic.load();
loop {
match atomic.compare_set_weak(¤t, Arc::new(20)) {
Ok(_) => break,
Err(actual) => current = actual,
}
}
assert_eq!(*atomic.load(), 20);Sourcepub fn compare_and_exchange(&self, current: &Arc<T>, new: Arc<T>) -> Arc<T>
pub fn compare_and_exchange(&self, current: &Arc<T>, new: Arc<T>) -> Arc<T>
Compares and exchanges the reference atomically, returning the previous reference.
If the current reference equals current (by pointer equality), sets
it to new and returns the old reference. Otherwise, returns the
actual current reference.
Uses AcqRel ordering on success and Acquire ordering on failure.
§Parameters
current- The expected current reference.new- The new reference to set if current matches.
§Returns
The reference before the operation.
§Note
Comparison uses pointer equality (Arc::ptr_eq), not value equality.
§Example
use prism3_rust_concurrent::atomic::AtomicRef;
use std::sync::Arc;
let atomic = AtomicRef::new(Arc::new(10));
let current = atomic.load();
let prev = atomic.compare_and_exchange(¤t, Arc::new(20));
assert!(Arc::ptr_eq(&prev, ¤t));
assert_eq!(*atomic.load(), 20);Sourcepub fn compare_and_exchange_weak(&self, current: &Arc<T>, new: Arc<T>) -> Arc<T>
pub fn compare_and_exchange_weak(&self, current: &Arc<T>, new: Arc<T>) -> Arc<T>
Weak version of compare-and-exchange.
May spuriously fail even when the comparison succeeds. Should be used in a loop.
Uses AcqRel ordering on success and Acquire ordering on failure.
§Parameters
current- The expected current reference.new- The new reference to set if current matches.
§Returns
The reference before the operation.
§Example
use prism3_rust_concurrent::atomic::AtomicRef;
use std::sync::Arc;
let atomic = AtomicRef::new(Arc::new(10));
let mut current = atomic.load();
loop {
let prev =
atomic.compare_and_exchange_weak(¤t, Arc::new(20));
if Arc::ptr_eq(&prev, ¤t) {
break;
}
current = prev;
}
assert_eq!(*atomic.load(), 20);Sourcepub fn fetch_update<F>(&self, f: F) -> Arc<T>
pub fn fetch_update<F>(&self, f: F) -> Arc<T>
Updates the reference using a function, returning the old reference.
§Memory Ordering
Internally uses a CAS loop with compare_set_weak, which uses
AcqRel on success and Acquire on failure. The loop ensures
eventual consistency even under high contention.
§Parameters
f- A function that takes the current reference and returns the new reference.
§Returns
The old reference before the update.
§Example
use prism3_rust_concurrent::atomic::AtomicRef;
use std::sync::Arc;
let atomic = AtomicRef::new(Arc::new(10));
let old = atomic.fetch_update(|x| Arc::new(*x * 2));
assert_eq!(*old, 10);
assert_eq!(*atomic.load(), 20);Examples found in repository?
24fn main() {
25 println!("=== Atomic Reference Example ===\n");
26
27 // Example 1: Basic reference operations
28 println!("1. Basic Reference Operations:");
29 let config = Arc::new(Config {
30 version: 1,
31 name: "initial".to_string(),
32 value: 100,
33 });
34 let atomic_config = AtomicRef::new(config.clone());
35
36 println!(" Initial config: {:?}", atomic_config.load());
37
38 let new_config = Arc::new(Config {
39 version: 2,
40 name: "updated".to_string(),
41 value: 200,
42 });
43 atomic_config.store(new_config);
44
45 println!(" Updated config: {:?}", atomic_config.load());
46
47 // Example 2: Compare-and-swap
48 println!("\n2. Compare-and-Swap:");
49 let config = Arc::new(Config {
50 version: 1,
51 name: "v1".to_string(),
52 value: 10,
53 });
54 let atomic_config = AtomicRef::new(config.clone());
55
56 let current = atomic_config.load();
57 let new_config = Arc::new(Config {
58 version: 2,
59 name: "v2".to_string(),
60 value: 20,
61 });
62
63 match atomic_config.compare_set(¤t, new_config) {
64 Ok(_) => println!(" CAS succeeded: {:?}", atomic_config.load()),
65 Err(actual) => println!(" CAS failed: {:?}", actual),
66 }
67
68 // Example 3: Functional updates
69 println!("\n3. Functional Updates:");
70 let config = Arc::new(Config {
71 version: 1,
72 name: "counter".to_string(),
73 value: 0,
74 });
75 let atomic_config = AtomicRef::new(config);
76
77 let old = atomic_config.fetch_update(|current| {
78 Arc::new(Config {
79 version: current.version + 1,
80 name: current.name.clone(),
81 value: current.value + 10,
82 })
83 });
84
85 println!(" Old config: {:?}", old);
86 println!(" New config: {:?}", atomic_config.load());
87
88 // Example 4: Multi-threaded updates
89 println!("\n4. Multi-threaded Updates:");
90 let config = Arc::new(Config {
91 version: 0,
92 name: "shared".to_string(),
93 value: 0,
94 });
95 let atomic_config = Arc::new(AtomicRef::new(config));
96 let mut handles = vec![];
97
98 for i in 0..10 {
99 let atomic_config = atomic_config.clone();
100 let handle = thread::spawn(move || {
101 for _ in 0..10 {
102 atomic_config.fetch_update(|current| {
103 Arc::new(Config {
104 version: current.version + 1,
105 name: current.name.clone(),
106 value: current.value + 1,
107 })
108 });
109 }
110 println!(" Thread {} completed", i);
111 });
112 handles.push(handle);
113 }
114
115 for handle in handles {
116 handle.join().unwrap();
117 }
118
119 let final_config = atomic_config.load();
120 println!(" Final config: {:?}", final_config);
121 println!(" Expected version: 100, actual: {}", final_config.version);
122 println!(" Expected value: 100, actual: {}", final_config.value);
123
124 println!("\n=== Example completed ===");
125}Sourcepub fn inner(&self) -> &AtomicPtr<T>
pub fn inner(&self) -> &AtomicPtr<T>
Gets a reference to the underlying standard library atomic type.
This allows direct access to the standard library’s atomic operations for advanced use cases that require fine-grained control over memory ordering.
§Memory Ordering
When using the returned reference, you have full control over memory ordering. Choose the appropriate ordering based on your specific synchronization requirements.
§Returns
A reference to the underlying std::sync::atomic::AtomicPtr<T>.
§Warning
Direct manipulation of the underlying pointer requires careful management of Arc reference counts to avoid memory leaks or use-after-free bugs.