]> git.lizzy.rs Git - rust.git/blob - src/libstd/sync/atomic.rs
Add verbose option to rustdoc in order to fix problem with --version
[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, INIT_ATOMIC_UINT};
90 //!
91 //! static GLOBAL_TASK_COUNT: AtomicUint = INIT_ATOMIC_UINT;
92 //!
93 //! let old_task_count = GLOBAL_TASK_COUNT.fetch_add(1, SeqCst);
94 //! println!("live tasks: {}", old_task_count + 1);
95 //! ```
96
97 #![allow(deprecated)]
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::{Ordering, Relaxed, Release, Acquire, AcqRel, SeqCst};
105 pub use core::atomic::{INIT_ATOMIC_BOOL, INIT_ATOMIC_INT, INIT_ATOMIC_UINT};
106 pub use core::atomic::fence;
107
108 /// An atomic, nullable unique pointer
109 ///
110 /// This can be used as the concurrency primitive for operations that transfer
111 /// owned heap objects across tasks.
112 #[unsafe_no_drop_flag]
113 #[deprecated = "no longer used; will eventually be replaced by a higher-level\
114                 concept like MVar"]
115 pub struct AtomicOption<T> {
116     p: AtomicUint,
117 }
118
119 impl<T: Send> AtomicOption<T> {
120     /// Create a new `AtomicOption`
121     pub fn new(p: Box<T>) -> AtomicOption<T> {
122         unsafe { AtomicOption { p: AtomicUint::new(mem::transmute(p)) } }
123     }
124
125     /// Create a new `AtomicOption` that doesn't contain a value
126     pub fn empty() -> AtomicOption<T> { AtomicOption { p: AtomicUint::new(0) } }
127
128     /// Store a value, returning the old value
129     #[inline]
130     pub fn swap(&self, val: Box<T>, order: Ordering) -> Option<Box<T>> {
131         let val = unsafe { mem::transmute(val) };
132
133         match self.p.swap(val, order) {
134             0 => None,
135             n => Some(unsafe { mem::transmute(n) }),
136         }
137     }
138
139     /// Remove the value, leaving the `AtomicOption` empty.
140     #[inline]
141     pub fn take(&self, order: Ordering) -> Option<Box<T>> {
142         unsafe { self.swap(mem::transmute(0u), order) }
143     }
144
145     /// Replace an empty value with a non-empty value.
146     ///
147     /// Succeeds if the option is `None` and returns `None` if so. If
148     /// the option was already `Some`, returns `Some` of the rejected
149     /// value.
150     #[inline]
151     pub fn fill(&self, val: Box<T>, order: Ordering) -> Option<Box<T>> {
152         unsafe {
153             let val = mem::transmute(val);
154             let expected = mem::transmute(0u);
155             let oldval = self.p.compare_and_swap(expected, val, order);
156             if oldval == expected {
157                 None
158             } else {
159                 Some(mem::transmute(val))
160             }
161         }
162     }
163
164     /// Returns `true` if the `AtomicOption` is empty.
165     ///
166     /// Be careful: The caller must have some external method of ensuring the
167     /// result does not get invalidated by another task after this returns.
168     #[inline]
169     pub fn is_empty(&self, order: Ordering) -> bool {
170         self.p.load(order) as uint == 0
171     }
172 }
173
174 #[unsafe_destructor]
175 impl<T: Send> Drop for AtomicOption<T> {
176     fn drop(&mut self) {
177         let _ = self.take(SeqCst);
178     }
179 }
180
181 #[cfg(test)]
182 mod test {
183     use prelude::{Some, None};
184     use super::*;
185
186     #[test]
187     fn option_empty() {
188         let option: AtomicOption<()> = AtomicOption::empty();
189         assert!(option.is_empty(SeqCst));
190     }
191
192     #[test]
193     fn option_swap() {
194         let p = AtomicOption::new(box 1i);
195         let a = box 2i;
196
197         let b = p.swap(a, SeqCst);
198
199         assert!(b == Some(box 1));
200         assert!(p.take(SeqCst) == Some(box 2));
201     }
202
203     #[test]
204     fn option_take() {
205         let p = AtomicOption::new(box 1i);
206
207         assert!(p.take(SeqCst) == Some(box 1));
208         assert!(p.take(SeqCst) == None);
209
210         let p2 = box 2i;
211         p.swap(p2, SeqCst);
212
213         assert!(p.take(SeqCst) == Some(box 2));
214     }
215
216     #[test]
217     fn option_fill() {
218         let p = AtomicOption::new(box 1i);
219         assert!(p.fill(box 2i, SeqCst).is_some()); // should fail; shouldn't leak!
220         assert!(p.take(SeqCst) == Some(box 1));
221
222         assert!(p.fill(box 2i, SeqCst).is_none()); // shouldn't fail
223         assert!(p.take(SeqCst) == Some(box 2));
224     }
225 }