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",
18 use sync
::{Mutex, Condvar}
;
20 /// A counting, blocking, semaphore.
22 /// Semaphores are a form of atomic counter where access is only granted if the
23 /// counter is a positive value. Each acquisition will block the calling thread
24 /// until the counter is positive, and each release will increment the counter
25 /// and unblock any threads if necessary.
30 /// #![feature(semaphore)]
32 /// use std::sync::Semaphore;
34 /// // Create a semaphore that represents 5 resources
35 /// let sem = Semaphore::new(5);
37 /// // Acquire one of the resources
40 /// // Acquire one of the resources for a limited period of time
42 /// let _guard = sem.access();
44 /// } // resources is released here
46 /// // Release our initially acquired resource
49 #[rustc_deprecated(since = "1.7.0",
50 reason
= "easily confused with system semaphores and not \
51 used enough to pull its weight")]
52 #[unstable(feature = "semaphore",
53 reason
= "the interaction between semaphores and the acquisition/release \
54 of resources is currently unclear",
56 pub struct Semaphore
{
61 /// An RAII guard which will release a resource acquired from a semaphore when
63 #[rustc_deprecated(since = "1.7.0",
64 reason
= "easily confused with system semaphores and not \
65 used enough to pull its weight")]
66 #[unstable(feature = "semaphore",
67 reason
= "the interaction between semaphores and the acquisition/release \
68 of resources is currently unclear",
70 pub struct SemaphoreGuard
<'a
> {
74 #[rustc_deprecated(since = "1.7.0",
75 reason
= "easily confused with system semaphores and not \
76 used enough to pull its weight")]
77 #[unstable(feature = "semaphore",
78 reason
= "the interaction between semaphores and the acquisition/release \
79 of resources is currently unclear",
82 /// Creates a new semaphore with the initial count specified.
84 /// The count specified can be thought of as a number of resources, and a
85 /// call to `acquire` or `access` will block until at least one resource is
86 /// available. It is valid to initialize a semaphore with a negative count.
87 pub fn new(count
: isize) -> Semaphore
{
89 lock
: Mutex
::new(count
),
94 /// Acquires a resource of this semaphore, blocking the current thread until
97 /// This method will block until the internal count of the semaphore is at
99 pub fn acquire(&self) {
100 let mut count
= self.lock
.lock().unwrap();
102 count
= self.cvar
.wait(count
).unwrap();
107 /// Release a resource from this semaphore.
109 /// This will increment the number of resources in this semaphore by 1 and
110 /// will notify any pending waiters in `acquire` or `access` if necessary.
111 pub fn release(&self) {
112 *self.lock
.lock().unwrap() += 1;
113 self.cvar
.notify_one();
116 /// Acquires a resource of this semaphore, returning an RAII guard to
117 /// release the semaphore when dropped.
119 /// This function is semantically equivalent to an `acquire` followed by a
120 /// `release` when the guard returned is dropped.
121 pub fn access(&self) -> SemaphoreGuard
{
123 SemaphoreGuard { sem: self }
127 #[stable(feature = "rust1", since = "1.0.0")]
128 impl<'a
> Drop
for SemaphoreGuard
<'a
> {
139 use super::Semaphore
;
140 use sync
::mpsc
::channel
;
144 fn test_sem_acquire_release() {
145 let s
= Semaphore
::new(1);
152 fn test_sem_basic() {
153 let s
= Semaphore
::new(1);
158 fn test_sem_as_mutex() {
159 let s
= Arc
::new(Semaphore
::new(1));
161 let _t
= thread
::spawn(move|| {
162 let _g
= s2
.access();
168 fn test_sem_as_cvar() {
169 /* Child waits and parent signals */
170 let (tx
, rx
) = channel();
171 let s
= Arc
::new(Semaphore
::new(0));
173 let _t
= thread
::spawn(move|| {
175 tx
.send(()).unwrap();
180 /* Parent waits and child signals */
181 let (tx
, rx
) = channel();
182 let s
= Arc
::new(Semaphore
::new(0));
184 let _t
= thread
::spawn(move|| {
189 tx
.send(()).unwrap();
193 fn test_sem_multi_resource() {
194 // Parent and child both get in the critical section at the same
195 // time, and shake hands.
196 let s
= Arc
::new(Semaphore
::new(2));
198 let (tx1
, rx1
) = channel();
199 let (tx2
, rx2
) = channel();
200 let _t
= thread
::spawn(move|| {
201 let _g
= s2
.access();
203 tx1
.send(()).unwrap();
206 tx2
.send(()).unwrap();
211 fn test_sem_runtime_friendly_blocking() {
212 let s
= Arc
::new(Semaphore
::new(1));
214 let (tx
, rx
) = channel();
217 thread
::spawn(move|| {
218 tx
.send(()).unwrap();
220 tx
.send(()).unwrap();
222 rx
.recv().unwrap(); // wait for child to come alive
224 rx
.recv().unwrap(); // wait for child to be done