]> git.lizzy.rs Git - rust.git/blob - src/libstd/sync/atomic.rs
doc: remove incomplete sentence
[rust.git] / src / libstd / sync / atomic.rs
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.
4 //
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.
10
11 //! Atomic types
12 //!
13 //! Atomic types provide primitive shared-memory communication between
14 //! threads, and are the building blocks of other concurrent
15 //! types.
16 //!
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.
21 //!
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].
25 //!
26 //! [1]: http://gcc.gnu.org/wiki/Atomic/GCCMM/AtomicSync
27 //!
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).
32 //!
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.
36 //!
37 //!
38 //! # Examples
39 //!
40 //! A simple spinlock:
41 //!
42 //! ```
43 //! use std::sync::Arc;
44 //! use std::sync::atomic::{AtomicUint, SeqCst};
45 //! use std::thread::Thread;
46 //!
47 //! fn main() {
48 //!     let spinlock = Arc::new(AtomicUint::new(1));
49 //!
50 //!     let spinlock_clone = spinlock.clone();
51 //!     Thread::spawn(move|| {
52 //!         spinlock_clone.store(0, SeqCst);
53 //!     }).detach();
54 //!
55 //!     // Wait for the other task to release the lock
56 //!     while spinlock.load(SeqCst) != 0 {}
57 //! }
58 //! ```
59 //!
60 //! Transferring a heap object with `AtomicOption`:
61 //!
62 //! ```
63 //! use std::sync::Arc;
64 //! use std::sync::atomic::{AtomicOption, SeqCst};
65 //! use std::thread::Thread;
66 //!
67 //! fn main() {
68 //!     struct BigObject;
69 //!
70 //!     let shared_big_object = Arc::new(AtomicOption::empty());
71 //!
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");
77 //!         } else {
78 //!             println!("other task hasn't sent big object yet");
79 //!         }
80 //!     }).detach();
81 //!
82 //!     shared_big_object.swap(box BigObject, SeqCst);
83 //! }
84 //! ```
85 //!
86 //! Keep a global count of live tasks:
87 //!
88 //! ```
89 //! use std::sync::atomic::{AtomicUint, SeqCst, ATOMIC_UINT_INIT};
90 //!
91 //! static GLOBAL_TASK_COUNT: AtomicUint = ATOMIC_UINT_INIT;
92 //!
93 //! let old_task_count = GLOBAL_TASK_COUNT.fetch_add(1, SeqCst);
94 //! println!("live tasks: {}", old_task_count + 1);
95 //! ```
96
97 #![stable]
98
99 use alloc::boxed::Box;
100 use core::mem;
101 use core::prelude::{Send, Drop, None, Option, Some};
102
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};
108
109 /// An atomic, nullable unique pointer
110 ///
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\
115                 concept like MVar"]
116 pub struct AtomicOption<T> {
117     p: AtomicUint,
118 }
119
120 #[allow(deprecated)]
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)) } }
125     }
126
127     /// Create a new `AtomicOption` that doesn't contain a value
128     pub fn empty() -> AtomicOption<T> { AtomicOption { p: AtomicUint::new(0) } }
129
130     /// Store a value, returning the old value
131     #[inline]
132     pub fn swap(&self, val: Box<T>, order: Ordering) -> Option<Box<T>> {
133         let val = unsafe { mem::transmute(val) };
134
135         match self.p.swap(val, order) {
136             0 => None,
137             n => Some(unsafe { mem::transmute(n) }),
138         }
139     }
140
141     /// Remove the value, leaving the `AtomicOption` empty.
142     #[inline]
143     pub fn take(&self, order: Ordering) -> Option<Box<T>> {
144         unsafe { self.swap(mem::transmute(0u), order) }
145     }
146
147     /// Replace an empty value with a non-empty value.
148     ///
149     /// Succeeds if the option is `None` and returns `None` if so. If
150     /// the option was already `Some`, returns `Some` of the rejected
151     /// value.
152     #[inline]
153     pub fn fill(&self, val: Box<T>, order: Ordering) -> Option<Box<T>> {
154         unsafe {
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 {
159                 None
160             } else {
161                 Some(mem::transmute(val))
162             }
163         }
164     }
165
166     /// Returns `true` if the `AtomicOption` is empty.
167     ///
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.
170     #[inline]
171     pub fn is_empty(&self, order: Ordering) -> bool {
172         self.p.load(order) as uint == 0
173     }
174 }
175
176 #[unsafe_destructor]
177 impl<T: Send> Drop for AtomicOption<T> {
178     fn drop(&mut self) {
179         let _ = self.take(SeqCst);
180     }
181 }
182
183 #[cfg(test)]
184 mod test {
185     use prelude::v1::*;
186     use super::*;
187
188     #[test]
189     fn option_empty() {
190         let option: AtomicOption<()> = AtomicOption::empty();
191         assert!(option.is_empty(SeqCst));
192     }
193
194     #[test]
195     fn option_swap() {
196         let p = AtomicOption::new(box 1i);
197         let a = box 2i;
198
199         let b = p.swap(a, SeqCst);
200
201         assert!(b == Some(box 1));
202         assert!(p.take(SeqCst) == Some(box 2));
203     }
204
205     #[test]
206     fn option_take() {
207         let p = AtomicOption::new(box 1i);
208
209         assert!(p.take(SeqCst) == Some(box 1));
210         assert!(p.take(SeqCst) == None);
211
212         let p2 = box 2i;
213         p.swap(p2, SeqCst);
214
215         assert!(p.take(SeqCst) == Some(box 2));
216     }
217
218     #[test]
219     fn option_fill() {
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));
223
224         assert!(p.fill(box 2i, SeqCst).is_none()); // shouldn't fail
225         assert!(p.take(SeqCst) == Some(box 2));
226     }
227 }