1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 //! Atomic types provide primitive shared-memory communication between
14 //! threads, and are the building blocks of other concurrent
17 //! This module defines atomic versions of a select number of primitive
18 //! types, including `AtomicBool`, `AtomicInt`, `AtomicUint`, and `AtomicOption`.
19 //! Atomic types present operations that, when used correctly, synchronize
20 //! updates between threads.
22 //! Each method takes an `Ordering` which represents the strength of
23 //! the memory barrier for that operation. These orderings are the
24 //! same as [C++11 atomic orderings][1].
26 //! [1]: http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync
28 //! Atomic variables are safe to share between threads (they implement `Sync`)
29 //! but they do not themselves provide the mechanism for sharing. The most
30 //! common way to share an atomic variable is to put it into an `Arc` (an
31 //! atomically-reference-counted shared pointer).
33 //! Most atomic types may be stored in static variables, initialized using
34 //! the provided static initializers like `INIT_ATOMIC_BOOL`. Atomic statics
35 //! are often used for lazy global initialization.
40 //! A simple spinlock:
43 //! use std::sync::Arc;
44 //! use std::sync::atomic::{AtomicUint, SeqCst};
45 //! use std::thread::Thread;
48 //! let spinlock = Arc::new(AtomicUint::new(1));
50 //! let spinlock_clone = spinlock.clone();
51 //! Thread::spawn(move|| {
52 //! spinlock_clone.store(0, SeqCst);
55 //! // Wait for the other task to release the lock
56 //! while spinlock.load(SeqCst) != 0 {}
60 //! Transferring a heap object with `AtomicOption`:
63 //! use std::sync::Arc;
64 //! use std::sync::atomic::{AtomicOption, SeqCst};
65 //! use std::thread::Thread;
70 //! let shared_big_object = Arc::new(AtomicOption::empty());
72 //! let shared_big_object_clone = shared_big_object.clone();
73 //! Thread::spawn(move|| {
74 //! let unwrapped_big_object = shared_big_object_clone.take(SeqCst);
75 //! if unwrapped_big_object.is_some() {
76 //! println!("got a big object from another task");
78 //! println!("other task hasn't sent big object yet");
82 //! shared_big_object.swap(box BigObject, SeqCst);
86 //! Keep a global count of live tasks:
89 //! use std::sync::atomic::{AtomicUint, SeqCst, ATOMIC_UINT_INIT};
91 //! static GLOBAL_TASK_COUNT: AtomicUint = ATOMIC_UINT_INIT;
93 //! let old_task_count = GLOBAL_TASK_COUNT.fetch_add(1, SeqCst);
94 //! println!("live tasks: {}", old_task_count + 1);
99 use alloc::boxed::Box;
101 use core::prelude::{Send, Drop, None, Option, Some};
103 pub use core::atomic::{AtomicBool, AtomicInt, AtomicUint, AtomicPtr};
104 pub use core::atomic::{INIT_ATOMIC_BOOL, INIT_ATOMIC_INT, INIT_ATOMIC_UINT};
105 pub use core::atomic::{ATOMIC_BOOL_INIT, ATOMIC_INT_INIT, ATOMIC_UINT_INIT};
106 pub use core::atomic::fence;
107 pub use core::atomic::Ordering::{mod, Relaxed, Release, Acquire, AcqRel, SeqCst};
109 /// An atomic, nullable unique pointer
111 /// This can be used as the concurrency primitive for operations that transfer
112 /// owned heap objects across tasks.
113 #[unsafe_no_drop_flag]
114 #[deprecated = "no longer used; will eventually be replaced by a higher-level\
116 pub struct AtomicOption<T> {
121 impl<T: Send> AtomicOption<T> {
122 /// Create a new `AtomicOption`
123 pub fn new(p: Box<T>) -> AtomicOption<T> {
124 unsafe { AtomicOption { p: AtomicUint::new(mem::transmute(p)) } }
127 /// Create a new `AtomicOption` that doesn't contain a value
128 pub fn empty() -> AtomicOption<T> { AtomicOption { p: AtomicUint::new(0) } }
130 /// Store a value, returning the old value
132 pub fn swap(&self, val: Box<T>, order: Ordering) -> Option<Box<T>> {
133 let val = unsafe { mem::transmute(val) };
135 match self.p.swap(val, order) {
137 n => Some(unsafe { mem::transmute(n) }),
141 /// Remove the value, leaving the `AtomicOption` empty.
143 pub fn take(&self, order: Ordering) -> Option<Box<T>> {
144 unsafe { self.swap(mem::transmute(0u), order) }
147 /// Replace an empty value with a non-empty value.
149 /// Succeeds if the option is `None` and returns `None` if so. If
150 /// the option was already `Some`, returns `Some` of the rejected
153 pub fn fill(&self, val: Box<T>, order: Ordering) -> Option<Box<T>> {
155 let val = mem::transmute(val);
156 let expected = mem::transmute(0u);
157 let oldval = self.p.compare_and_swap(expected, val, order);
158 if oldval == expected {
161 Some(mem::transmute(val))
166 /// Returns `true` if the `AtomicOption` is empty.
168 /// Be careful: The caller must have some external method of ensuring the
169 /// result does not get invalidated by another task after this returns.
171 pub fn is_empty(&self, order: Ordering) -> bool {
172 self.p.load(order) as uint == 0
177 impl<T: Send> Drop for AtomicOption<T> {
179 let _ = self.take(SeqCst);
190 let option: AtomicOption<()> = AtomicOption::empty();
191 assert!(option.is_empty(SeqCst));
196 let p = AtomicOption::new(box 1i);
199 let b = p.swap(a, SeqCst);
201 assert!(b == Some(box 1));
202 assert!(p.take(SeqCst) == Some(box 2));
207 let p = AtomicOption::new(box 1i);
209 assert!(p.take(SeqCst) == Some(box 1));
210 assert!(p.take(SeqCst) == None);
215 assert!(p.take(SeqCst) == Some(box 2));
220 let p = AtomicOption::new(box 1i);
221 assert!(p.fill(box 2i, SeqCst).is_some()); // should fail; shouldn't leak!
222 assert!(p.take(SeqCst) == Some(box 1));
224 assert!(p.fill(box 2i, SeqCst).is_none()); // shouldn't fail
225 assert!(p.take(SeqCst) == Some(box 2));