| Crates.io | atomic-counter |
| lib.rs | atomic-counter |
| version | 1.0.1 |
| created_at | 2017-09-08 09:32:12.58571+00 |
| updated_at | 2018-09-27 07:19:27.760007+00 |
| description | Atomic (thread-safe) counters for Rust |
| homepage | |
| repository | https://github.com/kosta/atomic-counter |
| max_upload_size | |
| id | 31040 |
| size | 18,256 |
Atomic (thread-safe) counters for Rust.
This crate contains an AtomicCounter trait
that can safely be shared across threads.
This crate provides two implementations:
RelaxedCounter which is suitable for
e.g. collecting metrics or generate IDs, but which does not provide
"Sequential Consistency".
RelaxedCounter uses Relaxed
memory ordering.
ConsistentCounter which provides the
same interface but is sequentially consistent. Use this counter if the
order of update from multiple threads is important.
ConsistentCounter uses Sequentially Consistent
memory ordering.
Both implementations are lock-free. Both are a very thin layer over
AtomicUsize
which is more powerful but might be harder to use correctly.
If you are just collecting metrics, the RelaxedCounter is probably right choice.
If you are generating IDs, but don't make strong assumptions (like allocating
memory based on the ID count), RelaxedCounter is probably the right choice.
If you are generating multiple IDs where you maintain an ordering
invariant (e.g. ID a is always greater than ID b), you need "Sequential
Consistency" and thus need to use ConsistentCounter. The same is true
for all use cases where the ordering of incrementing the counter is
important.
Note that in both implementations, no count is lost and all operations are atomic. The difference is only in how the order of operations are observed by different threads.
Assume a is 5 and b is 4. You always want to maintain a > b.
Thread 1 executes this code:
a.inc();
b.inc();
Thread 2 gets counts:
let a_local = a.get();
let b_local = b.get();
What are the values for a_local and b_local? That depends on the order
in which thread 1 and 2 have run:
a_local could still be 5 and b_local is still be 4 (e.g. if thread 2 ran before thread 1)a_local could be increment to 6 while b_local is still at 4 (e.g. if thread 1 and 2 ran in parallel)a_local could be increment to 6 and b_local be incremented to 5 (e.g. if thread 2 ran after thread 1).RelaxedCounter, we cannot make
assumption on the order of a.inc() and b.inc(). Thus, in this case
thread 2 can also observe a_local to be 5 (not incremented yet) but
b_local to be incremented to 5, breaking the invariant a > b.
Note that if thread 2 (or any other thread) get() the counts
again, at some point they will observe both values to be incremented.
No operations will be lost. It is only the ordering of the operations
that cannot be assumed if Ordering is Relaxed.So in order to maintain invariants such as a > b across multiple threads,
use ConsistentCounter.