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

Code before:
/// # Examples
///
/// Basic usage:
///
/// ```
/// use tokio::sync::{Semaphore, TryAcquireError};
///
/// #[tokio::main]
/// async fn main() {
///     let semaphore = Semaphore::new(3);
///
///     let a_permit = semaphore.acquire().await.unwrap();
///     let two_permits = semaphore.acquire_many(2).await.unwrap();
///
///     assert_eq!(semaphore.available_permits(), 0);
///
///     let permit_attempt = semaphore.try_acquire();
///     assert_eq!(permit_attempt.err(), Some(TryAcquireError::NoPermits));
/// }
/// ```
///
/// Limit number of incoming requests being handled at the same time.
///
/// Similar to limiting the numer of simultaneous opened files, network handles are a limited resource.
/// Allowing an unbounded amount of requests to be processed could result in a denial-of-service,
/// and many other issues.
///
/// However, in contrast to the file example, this example uses a non-static, `Arc`-wrapped `Semaphore`
/// for more fine-grained lifetime and ownership control. The `Arc` allows multiple threads and tasks
/// to share ownership of the semaphore. Here we create a shallow-copy of the `Arc<Semaphore>` reference
/// using `clone`. Then we acquire a permit through the `Arc` from the `Semaphore` via [`Semaphore::acquire_owned`],
/// and move it inside the task. This ensures no non-`'static` variables are referenced from within
/// said task.
///
/// If we leave the scope where the `Arc<Semaphore>` was defined, and references still exist in any
/// of our tasks to it, the `Semaphore` will continue to exist in a static-like context, until all
/// `Arc`s have been dropped.
///
/// ```compile_fail
/// use std::sync::Arc;
/// use tokio::sync::Semaphore;
/// use tokio::net::{TcpListener};
///
/// #[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();

Review comment (refactor):
If you want to say "similar to limiting the number of files", then you should move this example after the file example. Right now, it's unclear what you are referencing if you read the examples in order.

Also, there's a typo here.

Code after:
/// # Examples
///
/// Basic usage:
///
/// ```
/// use tokio::sync::{Semaphore, TryAcquireError};
///
/// #[tokio::main]
/// async fn main() {
///     let semaphore = Semaphore::new(3);
///
///     let a_permit = semaphore.acquire().await.unwrap();
///     let two_permits = semaphore.acquire_many(2).await.unwrap();
///
///     assert_eq!(semaphore.available_permits(), 0);
///
///     let permit_attempt = semaphore.try_acquire();
///     assert_eq!(permit_attempt.err(), Some(TryAcquireError::NoPermits));
/// }
/// ```
///
/// Limit the number of simultaneously opened files in your program.
///
/// Most operating systems have limits on the number of open file
/// handles. Even in systems without explicit limits, resource constraints
/// implicitly set an upper bound on the number of open files. If your
/// program attempts to open a large number of files and exceeds this
/// limit, it will result in an error.
///
/// This example uses a Semaphore with 100 permits. By acquiring a permit from
/// the Semaphore before accessing a file, you ensure that your program opens
/// no more than 100 files at a time. When trying to open the 101st
/// file, the program will wait until a permit becomes available before
/// proceeding to open another file.
/// ```
/// use std::io::Result;
/// use tokio::fs::File;
/// use tokio::sync::Semaphore;
/// use tokio::io::AsyncWriteExt;
///
/// static PERMITS: Semaphore = Semaphore::const_new(100);
///
/// async fn write_to_file(message: &[u8]) -> Result<()> {
///     let _permit = PERMITS.acquire().await.unwrap();
///     let mut buffer = File::create("example.txt").await?;
///     buffer.write_all(message).await?;
///     Ok(()) // Permit goes out of scope here, and is available again for acquisition
/// }
/// ```
///
/// Limit the number of incoming requests being handled at the same time.