simple_semaphore/lib.rs
1use std::{
2 sync::{Arc, Condvar, Mutex},
3 thread::available_parallelism,
4};
5
6/// A Semaphore maintains the number of permits it is still allowed to give.
7///
8/// * When `acquire()` is called and the semaphore still has permits to give, it will return a `Permit`. If there are no permits that can be given, it will wait for one permit to be given back from a thread so that it can return a new `Permit`.
9/// * When `try_acquire()` is called and the semaphore still has permits to give, it will return `Some(Permit)`. If there are no permits that can be given, it will return `None`.
10#[derive(Debug)]
11pub struct Semaphore {
12 permits: Mutex<usize>,
13 condvar: Condvar,
14}
15
16impl Semaphore {
17 /// Returns a new `Arc<Semaphore>` with the limit of permits chosen by you.
18 pub fn new(permits: usize) -> Arc<Self> {
19 Arc::new(Semaphore {
20 permits: Mutex::new(permits),
21 condvar: Condvar::new(),
22 })
23 }
24
25 /// Returns a new `Arc<Semaphore>` with the limit of permits set to the machine's parallelism value, usually CPU cores.
26 pub fn new_available_parallelism() -> Result<Arc<Self>, String> {
27 match available_parallelism() {
28 Ok(parallelism) => Ok(Arc::new(Semaphore {
29 permits: Mutex::new(parallelism.get()),
30 condvar: Condvar::new(),
31 })),
32 Err(err) => Err(err.to_string()),
33 }
34 }
35
36 /// Returns the number of available permits
37 #[deprecated(
38 since = "1.1.0",
39 note = "Please do not use this method anymore, there will be no replacement for it either"
40 )]
41 pub fn available_permits(self: &Arc<Self>) -> usize {
42 *self.permits.lock().unwrap()
43 }
44
45 /// Tries to get a `Permit`. If no more permits can be given, it will wait for one permit to be given back from a thread so that it can return a new `Permit`.
46 pub fn acquire(self: &Arc<Self>) -> Permit {
47 let mut permits = self.permits.lock().unwrap();
48 while *permits == 0 {
49 permits = self.condvar.wait(permits).unwrap();
50 }
51 *permits -= 1;
52 Permit {
53 semaphore: Arc::clone(self),
54 }
55 }
56
57 /// Tries to get a `Option<Permit>`. If no more permits can be given, it will return `None`.
58 pub fn try_acquire(self: &Arc<Self>) -> Option<Permit> {
59 let mut permits = self.permits.lock().unwrap();
60 if *permits > 0 {
61 *permits -= 1;
62 Some(Permit {
63 semaphore: Arc::clone(self),
64 })
65 } else {
66 None
67 }
68 }
69
70 /// Releases a permit. This is what `drop()` on `Permit` calls, ideally use `drop(permit)`.
71 pub fn release(&self) {
72 let mut permits = self.permits.lock().unwrap();
73 *permits += 1;
74 self.condvar.notify_one();
75 }
76}
77
78/// A permit that holds the Semaphore, so that `drop(permit)` can be called.
79#[derive(Debug)]
80pub struct Permit {
81 semaphore: Arc<Semaphore>,
82}
83
84impl Drop for Permit {
85 /// Releases the permit.
86 fn drop(&mut self) {
87 self.semaphore.release();
88 }
89}