Hone logo
Hone
Problems

Asynchronous Reader-Writer Lock in Rust

Implementing an asynchronous reader-writer lock (async rwlock) in Rust allows multiple readers or a single writer to access shared data concurrently, while ensuring data integrity. This is crucial for building concurrent applications where shared resources need to be protected from race conditions, particularly in asynchronous environments where threads are lightweight and numerous. This challenge asks you to implement a basic async rwlock that supports multiple concurrent readers and exclusive access for writers.

Problem Description

You are tasked with implementing an AsyncRwLock struct in Rust that provides asynchronous reader-writer lock functionality. The AsyncRwLock should allow multiple readers to acquire the lock concurrently, but only one writer can hold the lock at a time. Furthermore, no readers can acquire the lock while a writer holds it, and vice versa.

Key Requirements:

  • new(): A constructor that creates a new AsyncRwLock.
  • read_lock(): An asynchronous function that allows a reader to acquire a read lock. It should block the caller until a read lock can be acquired. Returns a ReadLockGuard.
  • write_lock(): An asynchronous function that allows a writer to acquire a write lock. It should block the caller until a write lock can be acquired. Returns a WriteLockGuard.
  • ReadLockGuard: A guard type that represents a held read lock. It should automatically release the read lock when it goes out of scope.
  • WriteLockGuard: A guard type that represents a held write lock. It should automatically release the write lock when it goes out of scope.
  • Fairness (Optional but Recommended): While not strictly required, consider implementing a fair queuing mechanism to prevent starvation of readers or writers. This can be achieved using a FIFO queue for waiting threads.

Expected Behavior:

  • Multiple read_lock() calls can succeed concurrently.
  • A write_lock() call will block until all existing read locks are released.
  • A write_lock() call will block until any existing write lock is released.
  • A read_lock() call will block while a write lock is held.
  • The guards (ReadLockGuard and WriteLockGuard) must automatically release the lock when they are dropped.

Edge Cases to Consider:

  • Spurious wakeups (handling Condvar wakeups correctly).
  • Multiple threads attempting to acquire the same lock simultaneously.
  • Lock contention under heavy load.
  • Potential for deadlock if not carefully designed.

Examples

Example 1:

Input: Two readers and one writer attempting to access a shared resource.
Output: Reader 1 acquires read lock, Reader 2 acquires read lock, Writer acquires write lock (blocking Reader 3), Writer releases write lock, Reader 3 acquires read lock.
Explanation: Demonstrates concurrent read access and exclusive write access.

Example 2:

Input: A writer attempting to acquire the lock while a reader holds it.
Output: The writer blocks until the reader releases the lock.
Explanation: Shows the writer blocking when a reader is active.

Example 3:

Input: Multiple writers attempting to acquire the lock simultaneously.
Output: The writers are queued and acquire the lock in the order they requested it (ideally, fairly).
Explanation: Demonstrates the queuing and fairness of the lock.

Constraints

  • The implementation must be thread-safe.
  • The implementation must be asynchronous, utilizing async/await.
  • The implementation should avoid deadlocks.
  • The implementation should be reasonably efficient, minimizing unnecessary blocking.
  • The AsyncRwLock should be usable with tokio or async-std runtime. (Assume tokio for this challenge).
  • The code should be well-documented and easy to understand.

Notes

  • You will likely need to use std::sync::Mutex, std::sync::Condvar, and tokio::sync::Mutex to implement the lock.
  • Consider using a RwLock from parking_lot as a starting point for inspiration, but adapt it to be asynchronous.
  • Think carefully about the order in which you acquire and release the locks to prevent deadlocks.
  • The fairness aspect is a bonus, but a functional, correct implementation is the primary goal.
  • Error handling is not required for this challenge. Focus on the core locking logic.
Loading editor...
rust