thread_share/locked.rs
1//! # Locked Module - ArcThreadShareLocked<T>
2//!
3//! This module provides `ArcThreadShareLocked<T>`, a safe zero-copy structure for
4//! data sharing between threads using read/write locks.
5//!
6//! ## 🚀 Overview
7//!
8//! `ArcThreadShareLocked<T>` is the **recommended alternative** to `ArcThreadShare<T>`
9//! when you need zero-copy operations with guaranteed thread safety. It provides
10//! the performance benefits of zero-copy while maintaining the safety guarantees
11//! of lock-based synchronization.
12//!
13//! ## Key Features
14//!
15//! - **Zero-Copy Operations**: No data cloning during access
16//! - **Guaranteed Thread Safety**: Uses `RwLock` for safe concurrent access
17//! - **High Performance**: Efficient `parking_lot` synchronization primitives
18//! - **Memory Efficiency**: Single copy of data shared across threads
19//! - **No Lost Updates**: All operations are guaranteed to succeed
20//! - **Predictable Behavior**: Consistent performance under all contention levels
21//!
22//! ## When to Use ArcThreadShareLocked<T>
23//!
24//! ### ✅ Perfect Use Cases
25//! - **Safe zero-copy operations** without the limitations of `ArcThreadShare<T>`
26//! - **High-frequency updates** where `ArcThreadShare<T>` would lose operations
27//! - **Critical data integrity** requirements
28//! - **Predictable performance** needs
29//! - **Large data structures** where cloning would be expensive
30//! - **Production applications** requiring reliability
31//!
32//! ### 🔄 Comparison with Other Patterns
33//!
34//! | Pattern | Zero-Copy | Thread Safety | Performance | Reliability |
35//! |---------|-----------|---------------|-------------|-------------|
36//! | **ThreadShare<T>** | ❌ | ✅ | Medium | ✅ |
37//! | **ArcThreadShare<T>** | ✅ | ⚠️ | High (unreliable) | ❌ |
38//! | **ArcThreadShareLocked<T>** | ✅ | ✅ | High | ✅ |
39//!
40//! ## Example Usage
41//!
42//! ### Basic Operations
43//! ```rust
44//! use thread_share::ArcThreadShareLocked;
45//!
46//! let counter = ArcThreadShareLocked::new(0);
47//!
48//! // Safe zero-copy operations
49//! counter.update(|x| *x += 1);
50//! counter.update(|x| *x += 2);
51//!
52//! assert_eq!(counter.get(), 3);
53//! ```
54//!
55//! ### From ThreadShare
56//! ```rust
57//! use thread_share::{share, ArcThreadShareLocked};
58//!
59//! let data = share!(String::from("Hello"));
60//! let arc_data = data.as_arc_locked();
61//! let locked_share = ArcThreadShareLocked::from_arc(arc_data);
62//!
63//! // Safe zero-copy with guaranteed thread safety
64//! locked_share.update(|s| s.push_str(" World"));
65//! ```
66//!
67//! ### High-Frequency Updates
68//! ```rust
69//! use thread_share::ArcThreadShareLocked;
70//! use std::thread;
71//!
72//! let counter = ArcThreadShareLocked::new(0);
73//! let clone = counter.clone();
74//!
75//! // Spawn multiple threads for high-frequency updates
76//! let handles: Vec<_> = (0..10).map(|_| {
77//! let counter_clone = clone.clone();
78//! thread::spawn(move || {
79//! for _ in 0..10000 {
80//! counter_clone.update(|x| *x += 1);
81//! }
82//! })
83//! }).collect();
84//!
85//! // Wait for all threads
86//! for handle in handles {
87//! handle.join().unwrap();
88//! }
89//!
90//! // All updates are guaranteed to succeed
91//! assert_eq!(counter.get(), 100000);
92//! ```
93//!
94//! ## Performance Characteristics
95//!
96//! - **Low Contention**: Excellent performance, minimal overhead
97//! - **Medium Contention**: Good performance with some lock contention
98//! - **High Contention**: Consistent performance, no lost operations
99//! - **Memory Usage**: Minimal overhead from lock structures
100//! - **Scalability**: Scales well with thread count
101//!
102//! ## Thread Safety
103//!
104//! `ArcThreadShareLocked<T>` automatically implements `Send` and `Sync` traits,
105//! making it safe to use across thread boundaries. The internal `RwLock` ensures
106//! that all operations are thread-safe and no data races can occur.
107//!
108//! ## Memory Management
109//!
110//! - **Arc**: Provides reference counting for shared ownership
111//! - **RwLock**: Ensures exclusive write access and concurrent read access
112//! - **No Box Allocation**: Unlike `ArcThreadShare<T>`, no per-operation allocations
113//! - **Efficient Locking**: Uses `parking_lot` for optimal performance
114//!
115//! ## Best Practices
116//!
117//! 1. **Use for zero-copy needs**: When you need to avoid cloning data
118//! 2. **Prefer over ArcThreadShare**: For reliable, production applications
119//! 3. **Monitor lock contention**: Use `read()` and `write()` methods appropriately
120//! 4. **Keep critical sections short**: Minimize time spent holding locks
121//! 5. **Use descriptive variable names**: Make it clear this is the locked version
122//!
123//! ## Migration from ArcThreadShare<T>
124//!
125//! If you're currently using `ArcThreadShare<T>` and experiencing issues:
126//!
127//! ```rust
128//! // Old: Unreliable atomic operations
129//! use thread_share::ArcThreadShare;
130//! let arc_share = ArcThreadShare::new(0);
131//! arc_share.update(|x| *x += 1); // May fail under contention
132//!
133//! // New: Reliable locked operations
134//! use thread_share::ArcThreadShareLocked;
135//! let locked_share = ArcThreadShareLocked::new(0);
136//! locked_share.update(|x| *x += 1); // Always succeeds
137//! ```
138//!
139//! ## Error Handling
140//!
141//! Unlike `ArcThreadShare<T>`, `ArcThreadShareLocked<T>` operations never fail
142//! due to contention. All operations are guaranteed to complete successfully,
143//! making error handling much simpler.
144//!
145//! ## Integration with ThreadShare
146//!
147//! `ArcThreadShareLocked<T>` integrates seamlessly with `ThreadShare<T>`:
148//!
149//! ```rust
150//! use thread_share::{share, ArcThreadShareLocked};
151//!
152//! let data = share!(vec![1, 2, 3]);
153//!
154//! // Get locked version for zero-copy operations
155//! let arc_data = data.as_arc_locked();
156//! let locked_share = ArcThreadShareLocked::from_arc(arc_data);
157//!
158//! // Use locked version in threads
159//! locked_share.update(|v| v.push(4));
160//!
161//! // Changes are visible in original ThreadShare
162//! assert_eq!(data.get(), vec![1, 2, 3, 4]);
163//! ```
164
165use parking_lot::RwLock;
166use std::sync::Arc;
167
168/// Helper structure for working with Arc<RwLock<T>> directly (with locks)
169///
170/// `ArcThreadShareLocked<T>` is the **recommended alternative** to `ArcThreadShare<T>`
171/// when you need zero-copy operations with guaranteed thread safety. It provides
172/// the performance benefits of zero-copy while maintaining the safety guarantees
173/// of lock-based synchronization.
174///
175/// ## Key Features
176///
177/// - **Zero-Copy Operations**: No data cloning during access
178/// - **Guaranteed Thread Safety**: Uses `RwLock` for safe concurrent access
179/// - **High Performance**: Efficient `parking_lot` synchronization primitives
180/// - **Memory Efficiency**: Single copy of data shared across threads
181/// - **No Lost Updates**: All operations are guaranteed to succeed
182/// - **Predictable Behavior**: Consistent performance under all contention levels
183///
184/// ## When to Use
185///
186/// - **Safe zero-copy operations** without the limitations of `ArcThreadShare<T>`
187/// - **High-frequency updates** where `ArcThreadShare<T>` would lose operations
188/// - **Critical data integrity** requirements
189/// - **Predictable performance** needs
190/// - **Production applications** requiring reliability
191///
192/// ## Example
193///
194/// ```rust
195/// use thread_share::ArcThreadShareLocked;
196///
197/// let counter = ArcThreadShareLocked::new(0);
198///
199/// // Safe zero-copy operations
200/// counter.update(|x| *x += 1);
201/// counter.update(|x| *x += 2);
202///
203/// assert_eq!(counter.get(), 3);
204/// ```
205///
206/// ## Performance
207///
208/// - **Low Contention**: Excellent performance, minimal overhead
209/// - **Medium Contention**: Good performance with some lock contention
210/// - **High Contention**: Consistent performance, no lost operations
211/// - **Memory Usage**: Minimal overhead from lock structures
212/// - **Scalability**: Scales well with thread count
213pub struct ArcThreadShareLocked<T> {
214 pub data: Arc<RwLock<T>>,
215}
216
217// Automatically implement Send and Sync for ArcThreadShareLocked
218unsafe impl<T> Send for ArcThreadShareLocked<T> {}
219unsafe impl<T> Sync for ArcThreadShareLocked<T> {}
220
221impl<T> Clone for ArcThreadShareLocked<T> {
222 fn clone(&self) -> Self {
223 Self {
224 data: Arc::clone(&self.data),
225 }
226 }
227}
228
229impl<T> ArcThreadShareLocked<T> {
230 /// Creates a new ArcThreadShareLocked with data
231 ///
232 /// This method creates a new `ArcThreadShareLocked<T>` instance with the provided data.
233 /// The data is wrapped in an `Arc<RwLock<T>>` for thread-safe sharing.
234 ///
235 /// ## Arguments
236 ///
237 /// * `data` - The initial data to share between threads
238 ///
239 /// ## Returns
240 ///
241 /// A new `ArcThreadShareLocked<T>` instance containing the data.
242 ///
243 /// ## Example
244 ///
245 /// ```rust
246 /// use thread_share::ArcThreadShareLocked;
247 ///
248 /// let counter = ArcThreadShareLocked::new(0);
249 /// let message = ArcThreadShareLocked::new(String::from("Hello"));
250 /// let data = ArcThreadShareLocked::new(vec![1, 2, 3]);
251 /// ```
252 pub fn new(data: T) -> Self {
253 let arc = Arc::new(RwLock::new(data));
254 Self { data: arc }
255 }
256
257 /// Creates from Arc<RwLock<T>>
258 ///
259 /// This method creates an `ArcThreadShareLocked<T>` from an existing `Arc<RwLock<T>>`.
260 /// Useful when you already have locked data from other sources, such as
261 /// from `ThreadShare<T>::as_arc_locked()`.
262 ///
263 /// ## Arguments
264 ///
265 /// * `arc` - An `Arc<RwLock<T>>` containing the data to share
266 ///
267 /// ## Returns
268 ///
269 /// A new `ArcThreadShareLocked<T>` instance sharing the same data.
270 ///
271 /// ## Example
272 ///
273 /// ```rust
274 /// use thread_share::{share, ArcThreadShareLocked};
275 ///
276 /// let data = share!(vec![1, 2, 3]);
277 /// let arc_data = data.as_arc_locked();
278 /// let locked_share = ArcThreadShareLocked::from_arc(arc_data);
279 ///
280 /// // Now you can use safe zero-copy operations
281 /// locked_share.update(|v| v.push(4));
282 /// ```
283 pub fn from_arc(arc: Arc<RwLock<T>>) -> Self {
284 Self { data: arc }
285 }
286
287 /// Gets a copy of data
288 ///
289 /// This method retrieves a copy of the current data. The operation is safe
290 /// but involves cloning the data.
291 ///
292 /// ## Requirements
293 ///
294 /// The type `T` must implement `Clone` trait.
295 ///
296 /// ## Returns
297 ///
298 /// A copy of the current data.
299 ///
300 /// ## Example
301 ///
302 /// ```rust
303 /// use thread_share::ArcThreadShareLocked;
304 ///
305 /// let counter = ArcThreadShareLocked::new(42);
306 /// let value = counter.get();
307 /// assert_eq!(value, 42);
308 /// ```
309 pub fn get(&self) -> T
310 where
311 T: Clone,
312 {
313 self.data.read().clone()
314 }
315
316 /// Gets a reference to data (no cloning!)
317 ///
318 /// This method provides read-only access to the data without cloning.
319 /// The returned guard holds the read lock until it's dropped.
320 ///
321 /// ## Returns
322 ///
323 /// A read guard that provides access to the data.
324 ///
325 /// ## Example
326 ///
327 /// ```rust
328 /// use thread_share::ArcThreadShareLocked;
329 ///
330 /// let data = ArcThreadShareLocked::new(vec![1, 2, 3]);
331 ///
332 /// // Get reference without cloning
333 /// {
334 /// let guard = data.get_ref();
335 /// assert_eq!(guard.len(), 3);
336 /// assert_eq!(guard[0], 1);
337 /// // Guard is automatically dropped here, releasing the lock
338 /// }
339 /// ```
340 ///
341 /// ## Note
342 ///
343 /// This method will block until the read lock can be acquired.
344 /// Multiple threads can read simultaneously.
345 /// For non-blocking behavior, use `try_get_ref()`.
346 pub fn get_ref(&self) -> parking_lot::RwLockReadGuard<'_, T> {
347 self.data.read()
348 }
349
350 /// Tries to get a reference to data without blocking
351 ///
352 /// This method attempts to acquire a read lock without blocking.
353 /// Returns `None` if the lock cannot be acquired immediately.
354 ///
355 /// ## Returns
356 ///
357 /// `Some(guard)` if the lock was acquired, `None` if it couldn't be acquired.
358 ///
359 /// ## Example
360 ///
361 /// ```rust
362 /// use thread_share::ArcThreadShareLocked;
363 ///
364 /// let data = ArcThreadShareLocked::new(vec![1, 2, 3]);
365 ///
366 /// // Try to get reference without blocking
367 /// if let Some(guard) = data.try_get_ref() {
368 /// assert_eq!(guard.len(), 3);
369 /// assert_eq!(guard[0], 1);
370 /// // Guard is automatically dropped here
371 /// } else {
372 /// // Lock was not available
373 /// }
374 ///
375 /// // Ensure data is still accessible
376 /// assert_eq!(data.get(), vec![1, 2, 3]);
377 /// ```
378 pub fn try_get_ref(&self) -> Option<parking_lot::RwLockReadGuard<'_, T>> {
379 self.data.try_read()
380 }
381
382 /// Gets a mutable reference to data (no cloning!)
383 ///
384 /// This method provides mutable access to the data without cloning.
385 /// The returned guard holds the write lock until it's dropped.
386 ///
387 /// ## Returns
388 ///
389 /// A write guard that provides mutable access to the data.
390 ///
391 /// ## Example
392 ///
393 /// ```rust
394 /// use thread_share::ArcThreadShareLocked;
395 ///
396 /// let data = ArcThreadShareLocked::new(vec![1, 2, 3]);
397 ///
398 /// // Get mutable reference without cloning
399 /// {
400 /// let mut guard = data.get_mut();
401 /// guard.push(4);
402 /// // Guard is automatically dropped here, releasing the lock
403 /// }
404 ///
405 /// assert_eq!(data.get(), vec![1, 2, 3, 4]);
406 /// ```
407 ///
408 /// ## Warning
409 ///
410 /// This method will block until the write lock can be acquired.
411 /// In high-contention scenarios, this can cause delays.
412 /// For non-blocking behavior, use `try_get_mut()`.
413 ///
414 /// ## Best Practices
415 ///
416 /// - Keep critical sections short to minimize lock contention
417 /// - Always drop the guard explicitly in complex scenarios
418 /// - Consider using `try_get_mut()` for non-blocking operations
419 pub fn get_mut(&self) -> parking_lot::RwLockWriteGuard<'_, T> {
420 self.data.write()
421 }
422
423 /// Tries to get a mutable reference to data without blocking
424 ///
425 /// This method attempts to acquire a write lock without blocking.
426 /// Returns `None` if the lock cannot be acquired immediately.
427 ///
428 /// ## Returns
429 ///
430 /// `Some(guard)` if the lock was acquired, `None` if it couldn't be acquired.
431 ///
432 /// ## Example
433 ///
434 /// ```rust
435 /// use thread_share::ArcThreadShareLocked;
436 ///
437 /// let data = ArcThreadShareLocked::new(vec![1, 2, 3]);
438 ///
439 /// // Try to get mutable reference without blocking
440 /// if let Some(mut guard) = data.try_get_mut() {
441 /// guard.push(4);
442 /// // Guard is automatically dropped here
443 /// }
444 ///
445 /// // Ensure data is still accessible
446 /// assert_eq!(data.get(), vec![1, 2, 3, 4]);
447 /// ```
448 pub fn try_get_mut(&self) -> Option<parking_lot::RwLockWriteGuard<'_, T>> {
449 self.data.try_write()
450 }
451
452 /// Sets data
453 ///
454 /// This method replaces the current data with new data.
455 ///
456 /// ## Arguments
457 ///
458 /// * `new_data` - The new data to set
459 ///
460 /// ## Example
461 ///
462 /// ```rust
463 /// use thread_share::ArcThreadShareLocked;
464 ///
465 /// let counter = ArcThreadShareLocked::new(0);
466 /// counter.set(100);
467 /// assert_eq!(counter.get(), 100);
468 /// ```
469 pub fn set(&self, new_data: T) {
470 let mut data = self.data.write();
471 *data = new_data;
472 }
473
474 /// Updates data using a function
475 ///
476 /// This method allows you to modify the data through a closure.
477 /// The operation is guaranteed to succeed and is thread-safe.
478 ///
479 /// ## Arguments
480 ///
481 /// * `f` - Closure that receives a mutable reference to the data
482 ///
483 /// ## Example
484 ///
485 /// ```rust
486 /// use thread_share::ArcThreadShareLocked;
487 ///
488 /// let counter = ArcThreadShareLocked::new(0);
489 ///
490 /// counter.update(|x| *x += 1);
491 /// assert_eq!(counter.get(), 1);
492 ///
493 /// counter.update(|x| *x *= 2);
494 /// assert_eq!(counter.get(), 2);
495 /// ```
496 pub fn update<F>(&self, f: F)
497 where
498 F: FnOnce(&mut T),
499 {
500 let mut data = self.data.write();
501 f(&mut data);
502 }
503
504 /// Reads data through a function
505 ///
506 /// This method provides read-only access to the data through a closure.
507 /// Multiple threads can read simultaneously.
508 ///
509 /// ## Arguments
510 ///
511 /// * `f` - Closure that receives a reference to the data
512 ///
513 /// ## Returns
514 ///
515 /// The result of the closure execution.
516 ///
517 /// ## Example
518 ///
519 /// ```rust
520 /// use thread_share::ArcThreadShareLocked;
521 ///
522 /// let data = ArcThreadShareLocked::new(vec![1, 2, 3]);
523 ///
524 /// let length = data.read(|v| v.len());
525 /// assert_eq!(length, 3);
526 ///
527 /// let sum: i32 = data.read(|v| v.iter().sum());
528 /// assert_eq!(sum, 6);
529 /// ```
530 pub fn read<F, R>(&self, f: F) -> R
531 where
532 F: FnOnce(&T) -> R,
533 {
534 let data = self.data.read();
535 f(&data)
536 }
537
538 /// Writes data through a function
539 ///
540 /// This method provides mutable access to the data through a closure.
541 /// Only one thread can write at a time.
542 ///
543 /// ## Arguments
544 ///
545 /// * `f` - Closure that receives a mutable reference to the data
546 ///
547 /// ## Returns
548 ///
549 /// The result of the closure execution.
550 ///
551 /// ## Example
552 ///
553 /// ```rust
554 /// use thread_share::ArcThreadShareLocked;
555 ///
556 /// let data = ArcThreadShareLocked::new(vec![1, 2, 3]);
557 ///
558 /// let length = data.write(|v| {
559 /// v.push(4);
560 /// v.len()
561 /// });
562 ///
563 /// assert_eq!(length, 4);
564 /// assert_eq!(data.get(), vec![1, 2, 3, 4]);
565 /// ```
566 pub fn write<F, R>(&self, f: F) -> R
567 where
568 F: FnOnce(&mut T) -> R,
569 {
570 let mut data = self.data.write();
571 f(&mut data)
572 }
573}