Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up

A downward counter (CountDownLatch) which can be used to synchronize threads or coordinate tasks

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT
NotificationsYou must be signed in to change notification settings

mirromutth/latches

Repository files navigation

Crates.iodocs.rsbuild statuscodecovdownloadlicense

A latch is a downward counter which can be used to synchronize threads or coordinate tasks. The value of the counter is initialized on creation. Threads/tasks may block/suspend on the latch until the counter is decremented to 0.

In contrast tostd::sync::Barrier, it is a one-shot phenomenon, that mean the counter will not be reset after reaching 0. Instead, it has the useful property that it does not make them wait for the counter to reach 0 by callingcount_down() orarrive(). This also means that it can be decremented by a participating thread/task more than once.

See alsostd::latch in C++ 20,java.util.concurrent.CountDownLatch in Java,Concurrent::CountDownLatch inconcurrent-ruby.

Quick Start

Thesync implementation withatomic-wait by default features:

cargo add latches

Thetask implementation withstd:

cargo add latches --no-default-features --features task --features std

Thefutex implementation:

cargo add latches --no-default-features --features futex

See alsoWhich One Should Be Used?

It can be used withno_std when thestd feature is not enabled.

Usage

Wait For Completion

use std::{sync::Arc, thread};// Naming rule: `latches::{implementation-name}::Latch`.use latches::sync::Latch;let latch =Arc::new(Latch::new(10));for _in0..10{let latch = latch.clone();    thread::spawn(move || latch.count_down());}// Waits 10 threads complete their works.// Requires `.await` if it is the `task` implementation.latch.wait();

Gate

use std::{sync::Arc, thread};// Naming rule: `latches::{implementation-name}::Latch`.use latches::sync::Latch;let gate =Arc::new(Latch::new(1));for _in0..10{let gate = gate.clone();    thread::spawn(move ||{// Waits for the gate signal.// Requires `.await` if it is the `task` implementation.        gate.wait();// Do some work after gate.});}// Allows 10 threads start their works.gate.count_down();

Implementations

Sync

Thesync implementation is the default implementation of threads.

Feature dependencies:

  • Addstd feature will make it usestd::sync::Mutex andstd::sync::Condvar as condition variables, it supports timeouts
  • Ifstd is disabled, addatomic-wait feature will make it useatomic-wait as condition variables, it does not support timeouts
  • If bothstd andatomic-wait are disabled, it will throw a compile error

Bothatomic-wait andsync are enabled in default features for easy-to-use. So if you want to usesync withstd and don't want to import the unnecessary crateatomic-wait, please disable default features.

Futex

Thefutex implementation is similar to popular implementations of C++20std::latch, which provides slightly better performance compared to thesync implementation.

It does not support timeouts for waiting.

Feature dependencies:

  • It depends on featureatomic-wait and crateatomic-wait, and cannot be disabled

Task

Thetask implementation is typically used to coordinate asynchronous tasks.

It requires extern cratealloc if inno_std.

Feature dependencies:

  • Addstd feature will make it usestd::sync::Mutex as thread mutexes on waker collection
  • Ifstd is disabled, addatomic-wait feature will make it use [atomic-wait][atomic-wait] as thread mutexes on waker collection
  • If bothstd andatomic-wait are disabled, it will use spinlocks as thread mutexes on waker collection

Similarities and differences

Similarities:

  • All implementations are based on atomic, so will not work on platforms that do not support atomic, i.e.#[cfg(target_has_atomic)]
  • All implementations can be used onno_std if thestd feature does not be enabled
  • All methods except waits: do not needasync/await

Differences:

synctaskfutex
counter typeusizeusizeu32
mutexesstd oratomic-waitstd,atomic-wait, or spinlockNo mutex*
waitsBlockingFuturesBlocking
timeoutsRequriesstdRequries an async timerNot support

* No mutex doesn't mean it doesn't need to eliminate race conditions, in fact it uses Futex (i.e.atomic-wait) instead

Which One Should Be Used?

If your project is usingasync/await tasks, use thetask implementation. Add it withstd oratomic-wait feature might make it more concurrency-friendly forgate scenarios. Like following:

cargo add latches --no-default-features --features task --feature atomic-wait

If the amount of concurrency in your project is small, use thefutex implementation. Like following:

cargo add latches --no-default-features --features futex

Otherwise, use thesync implementation. It has the same counter typeusize as thetask implementation andstd::sync::Barrier. Add it withstd feature will make it supports timeouts. Note that it should be used with one of thestd oratomic-wait features, otherwise a compilation error will be thrown. Like following:

# Both `sync` and `atomic-wait` are enabled in default featurescargo add latches

Or enablestd feature for timeouts support:

cargo add latches --no-default-features --features sync --features std

Under a large amount of concurrency, there is no obvious performance gap between thefutex implementation and thesync implementation.

Additionally, if you are migrating C++ code to Rust, using afutex implementation may be an approach which makes more conservative, e.g. similar memory usage, ABI calls, etc. Note that thefutex implementation has no undefined behavior, which is not like thestd::latch in C++.

Performance

Run Benchmarks

Run benchmarks for all implementations withatomic-wait (thefutex implementation depends onatomic-wait):

cargo bench --package benches

Run benchmarks with thesync implementation withstd:

cargo bench --package benches --no-default-features --features sync --features std

Run benchmarks with thetask implementation withatomic-wait:

cargo bench --package benches --no-default-features --features task --features atomic-wait

Or run benchmarks withstd and comparison group:

cargo bench --package benches --features std --features comparison

etc.

Overall benchmarks include thread scheduling overhead, andLatch is much faster than thread scheduling, so there may be timing jitter and large standard deviations. All overall benchmarks will have name postfix-overall.

The asynchronous comparison groups are also atomic-based and depend on specific async libraries such astokio andasync-std.

The synchronous comparison group usesMutex state instead of atomic.

License

Latches is released under the terms of either theMIT License or theApache License Version 2.0, at your option.

About

A downward counter (CountDownLatch) which can be used to synchronize threads or coordinate tasks

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Stars

Watchers

Forks

Packages

No packages published

Languages


[8]ページ先頭

©2009-2025 Movatter.jp