Hone logo
Hone
Problems

Concurrent Counter with Thread Safety

This challenge focuses on implementing a thread-safe counter in Rust. Rust's ownership and borrowing system provides powerful tools for ensuring memory safety, but achieving thread safety requires careful consideration of shared mutable state. You'll be building a counter that can be safely incremented by multiple threads concurrently.

Problem Description

You are tasked with creating a Counter struct that provides a thread-safe mechanism for incrementing and retrieving the current count. The Counter should be initialized with an initial value. It must provide the following methods:

  • new(initial_value: i32) -> Counter: Creates a new Counter with the given initial value.
  • increment(): Increments the counter by 1. This method must be thread-safe.
  • value() -> i32: Returns the current value of the counter. This method must be thread-safe.

The key requirement is that multiple threads can concurrently call increment() without causing data races or inconsistent state. Rust's concurrency primitives (like Mutex or RwLock) should be used to achieve this.

Expected Behavior:

  • Multiple threads calling increment() concurrently should eventually reflect in the value() method.
  • The value() method should always return a consistent and accurate count, even when called concurrently with increment().
  • The program should not panic due to data races or other concurrency issues.

Edge Cases to Consider:

  • High contention: Many threads attempting to increment the counter simultaneously.
  • Rapid increment and value retrieval: Threads rapidly incrementing and then immediately retrieving the value.
  • Initial value of zero.
  • Large number of increments.

Examples

Example 1:

Input: Two threads, each calling `increment()` 1000 times.
Output: The final value of the counter should be 2000.
Explanation: Each thread increments the counter 1000 times, so the total increment is 2000.

Example 2:

Input: Five threads, each calling `increment()` 500 times, followed by a call to `value()`.
Output: The final value of the counter should be 2500. All calls to `value()` should return 2500 after all threads have finished.
Explanation: Each thread increments the counter 500 times, so the total increment is 2500.

Example 3: (Edge Case - High Contention)

Input: 100 threads, each calling `increment()` 100 times concurrently.
Output: The final value of the counter should be 10000.
Explanation:  Demonstrates the thread safety under high contention.

Constraints

  • The Counter struct must be thread-safe.
  • The increment() method must be atomic with respect to other increment() calls.
  • The value() method must return a consistent value even when called concurrently with increment().
  • The solution should be reasonably efficient. While performance is not the primary focus, avoid unnecessary overhead.
  • The initial value can be any i32 value.
  • The number of threads incrementing the counter can be arbitrarily large (within reasonable system limits).

Notes

  • Consider using Rust's standard library concurrency primitives like Mutex or RwLock.
  • Think about the order of operations when incrementing and retrieving the value to avoid race conditions.
  • Testing with multiple threads is crucial to verify thread safety. Use the std::thread module to create and manage threads.
  • Rust's borrow checker will help you catch many concurrency errors at compile time, but thorough testing is still essential.
  • Focus on correctness first, then consider performance optimizations if needed.
Loading editor...
rust