Repository: tokio-rs/tokio
File: tokio/src/sync/semaphore.rs (Rust)

Code before:
/// are a limited resource. Allowing an unbounded amount of requests to be processed
/// could result in a denial-of-service, among many other issues.
///
/// However, in contrast to the file example, this example uses an `Arc<Semaphore>`.
/// Before we spawn a new task to process a request, we must acquire a permit from
/// this semaphore, in order to limit usage of system resources (like file descriptors,
/// memory usage, CPU time, etc.). Once acquired, a new task is spawned; and once
/// finished, the permit is dropped inside of the task to allow others to spawn.
/// Permits must be acquired via [`Semaphore::acquire_owned`], in order to be
/// movable across the task boundary. Contrastingly, if the semaphore were a global,
/// as in the file-limiting example, only ['Semaphore::acquire'] would be necessary.
/// This is because a `Permit<'static>` would be returned, which is movable across
/// task boundaries, since the semaphore lives forever.
///
/// ```no_run
/// use std::sync::Arc;
/// use tokio::sync::Semaphore;
/// use tokio::net::{TcpListener, TcpStream};
///
/// #[tokio::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
///     let semaphore = Arc::new(Semaphore::new(3));
///     let listener = TcpListener::bind("127.0.0.1:8080").await?;
///
///     loop {
///         // Acquire permit before accepting, to avoid needlessly taking up a (finite) file descriptor
///         let permit = semaphore.clone().acquire_owned().await.unwrap();
///         let (mut socket, _) = listener.accept().await?;
///
///         tokio::spawn(async move {
///             // Do work using the socket.
///             handle_connection(&mut socket).await;
///             // Drop socket while the permit is still live.
///             drop(socket);
///             // Drop the permit, so more tasks can be created.
///             drop(permit);
///         });
///     }
/// }
///
/// # async fn handle_connection(socket: &mut TcpStream) {
/// #   // Do work
/// # }
/// ```
///
/// [`PollSemaphore`]: https://docs.rs/tokio-util/latest/tokio_util/sync/struct.PollSemaphore.html
/// [`Semaphore::acquire_owned`]: crate::sync::Semaphore::acquire_owned
#[derive(Debug)]
pub struct Semaphore {
    /// The low level semaphore
    ll_sem: ll::Semaphore,

Review comment (suggestion):
I don't think using finite like this is grammatically correct.
```suggestion
///         // Acquire permit before accepting the next socket.
```

Code after:
/// are a limited resource. Allowing an unbounded amount of requests to be processed
/// could result in a denial-of-service, among many other issues.
///
/// This example uses an `Arc<Semaphore>` instead of a global variable.
/// To limit the number of requests that can be processed at the time,
/// we acquire a permit for each task before spawning it. Once acquired,
/// a new task is spawned; and once finished, the permit is dropped inside
/// of the task to allow others to spawn. Permits must be acquired via
/// [`Semaphore::acquire_owned`] to be movable across the task boundary.
/// (Since our semaphore is not a global variable — if it was, then `acquire` would be enough.)
///
/// ```no_run
/// use std::sync::Arc;
/// use tokio::sync::Semaphore;
/// use tokio::net::TcpListener;
///
/// #[tokio::main]
/// async fn main() -> std::io::Result<()> {
///     let semaphore = Arc::new(Semaphore::new(3));
///     let listener = TcpListener::bind("127.0.0.1:8080").await?;
///
///     loop {
///         // Acquire permit before accepting the next socket.
///         //
///         // We use `acquire_owned` so that we can move `permit` into
///         // other tasks.
///         let permit = semaphore.clone().acquire_owned().await.unwrap();
///         let (mut socket, _) = listener.accept().await?;
///
///         tokio::spawn(async move {
///             // Do work using the socket.
///             handle_connection(&mut socket).await;
///             // Drop socket while the permit is still live.
///             drop(socket);
///             // Drop the permit, so more tasks can be created.
///             drop(permit);
///         });
///     }
/// }
/// # async fn handle_connection(_socket: &mut tokio::net::TcpStream) {
/// #   // Do work
/// # }
/// ```
///
/// [`PollSemaphore`]: https://docs.rs/tokio-util/latest/tokio_util/sync/struct.PollSemaphore.html
/// [`Semaphore::acquire_owned`]: crate::sync::Semaphore::acquire_owned
#[derive(Debug)]
pub struct Semaphore {
    /// The low level semaphore
    ll_sem: ll::Semaphore,
    #[cfg(all(tokio_unstable, feature = "tracing"))]