1 // Copyright 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.
11 #![unstable(feature = "semaphore",
12 reason = "the interaction between semaphores and the acquisition/release \
13 of resources is currently unclear",
17 use sync::{Mutex, Condvar};
19 /// A counting, blocking, semaphore.
21 /// Semaphores are a form of atomic counter where access is only granted if the
22 /// counter is a positive value. Each acquisition will block the calling thread
23 /// until the counter is positive, and each release will increment the counter
24 /// and unblock any threads if necessary.
29 /// #![feature(semaphore)]
31 /// use std::sync::Semaphore;
33 /// // Create a semaphore that represents 5 resources
34 /// let sem = Semaphore::new(5);
36 /// // Acquire one of the resources
39 /// // Acquire one of the resources for a limited period of time
41 /// let _guard = sem.access();
43 /// } // resources is released here
45 /// // Release our initially acquired resource
48 pub struct Semaphore {
53 /// An RAII guard which will release a resource acquired from a semaphore when
55 pub struct SemaphoreGuard<'a> {
60 /// Creates a new semaphore with the initial count specified.
62 /// The count specified can be thought of as a number of resources, and a
63 /// call to `acquire` or `access` will block until at least one resource is
64 /// available. It is valid to initialize a semaphore with a negative count.
65 pub fn new(count: isize) -> Semaphore {
67 lock: Mutex::new(count),
72 /// Acquires a resource of this semaphore, blocking the current thread until
75 /// This method will block until the internal count of the semaphore is at
77 pub fn acquire(&self) {
78 let mut count = self.lock.lock().unwrap();
80 count = self.cvar.wait(count).unwrap();
85 /// Release a resource from this semaphore.
87 /// This will increment the number of resources in this semaphore by 1 and
88 /// will notify any pending waiters in `acquire` or `access` if necessary.
89 pub fn release(&self) {
90 *self.lock.lock().unwrap() += 1;
91 self.cvar.notify_one();
94 /// Acquires a resource of this semaphore, returning an RAII guard to
95 /// release the semaphore when dropped.
97 /// This function is semantically equivalent to an `acquire` followed by a
98 /// `release` when the guard returned is dropped.
99 pub fn access(&self) -> SemaphoreGuard {
101 SemaphoreGuard { sem: self }
105 #[stable(feature = "rust1", since = "1.0.0")]
106 impl<'a> Drop for SemaphoreGuard<'a> {
117 use super::Semaphore;
118 use sync::mpsc::channel;
122 fn test_sem_acquire_release() {
123 let s = Semaphore::new(1);
130 fn test_sem_basic() {
131 let s = Semaphore::new(1);
136 fn test_sem_as_mutex() {
137 let s = Arc::new(Semaphore::new(1));
139 let _t = thread::spawn(move|| {
140 let _g = s2.access();
146 fn test_sem_as_cvar() {
147 /* Child waits and parent signals */
148 let (tx, rx) = channel();
149 let s = Arc::new(Semaphore::new(0));
151 let _t = thread::spawn(move|| {
153 tx.send(()).unwrap();
158 /* Parent waits and child signals */
159 let (tx, rx) = channel();
160 let s = Arc::new(Semaphore::new(0));
162 let _t = thread::spawn(move|| {
167 tx.send(()).unwrap();
171 fn test_sem_multi_resource() {
172 // Parent and child both get in the critical section at the same
173 // time, and shake hands.
174 let s = Arc::new(Semaphore::new(2));
176 let (tx1, rx1) = channel();
177 let (tx2, rx2) = channel();
178 let _t = thread::spawn(move|| {
179 let _g = s2.access();
181 tx1.send(()).unwrap();
184 tx2.send(()).unwrap();
189 fn test_sem_runtime_friendly_blocking() {
190 let s = Arc::new(Semaphore::new(1));
192 let (tx, rx) = channel();
195 thread::spawn(move|| {
196 tx.send(()).unwrap();
198 tx.send(()).unwrap();
200 rx.recv().unwrap(); // wait for child to come alive
202 rx.recv().unwrap(); // wait for child to be done