Skip to main content

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}