Provides multi-threaded access to a single Vec\ Add this to your Cargo.toml: General purpose RangeLock: ``` {.rust}
extern crate rangelock;
use rangelock::RangeLock;
use std::sync::{Arc, Barrier};
use std::thread; // The data that will simultaneously be accessed from the threads.
let data = vec![10, 11, 12, 13]; // Embed the data in a RangeLock
// and clone atomic references to it for the threads.
let datalock0 = Arc::new(RangeLock::new(data));
let datalock1 = Arc::clone(&datalock0);
let datalock2 = Arc::clone(&data_lock0); // Thread barrier, only for demonstration purposes.
let barrier0 = Arc::new(Barrier::new(2));
let barrier1 = Arc::clone(&barrier0); // Spawn first thread.
let thread0 = thread::spawn(move || {
{
let mut guard = datalock0.trylock(0..2).expect("T0: Failed to lock 0..2");
guard[0] = 100; // Write to data[0]
}
barrier0.wait(); // Synchronize with second thread.
{
let guard = datalock0.trylock(2..4).expect("T0: Failed to lock 2..4");
assert_eq!(guard[0], 200); // Read from data[2]
}
}); // Spawn second thread.
let thread1 = thread::spawn(move || {
{
let mut guard = datalock1.trylock(2..4).expect("T1: Failed to lock 2..4");
guard[0] = 200; // Write to data[2]
}
barrier1.wait(); // Synchronize with first thread.
{
let guard = datalock1.trylock(0..2).expect("T1: Failed to lock 0..2");
assert_eq!(guard[0], 100); // Read from data[0]
}
}); // Wait for both threads to finish and check result.
thread0.join().expect("Thread 0 failed");
thread1.join().expect("Thread 1 failed"); // Unwrap the data from the lock.
let data = Arc::tryunwrap(datalock2).expect("Arc unwrap failed").into_inner(); // Check the data that has been modified by the threads.
assert_eq!(data, vec![100, 11, 200, 13]);
``` The RepRangeLock is a restricted range lock, that provides interleaved
patterns of slices to the threads. Locking a RepRangeLock is more lightweight than locking a RangeLock. Please see the example below. ``` {.rust}
use range_lock::RepRangeLock;
use std::sync::Arc;
use std::thread; let data = vec![1, 2, 3, 4, 5, 6, // <- cycle 0
7, 8, 9, 10, 11, 12]; // <- cycle 1
// ^--^ ^---^ ^----^
// | | |
// offset-0 offset-1 offset-2 let lock = Arc::new(RepRangeLock::new(data,
2, // slicelen: Each slice has 2 elements.
3)); // cyclelen: Each cycle has 3 slices (offsets).
let lock0 = Arc::clone(&lock);
let lock1 = Arc::clone(&lock);
let lock2 = Arc::clone(&lock); let thread0 = thread::spawn(move || {
// Lock slice offset 0:
let mut guard = lock0.try_lock(0).expect("Failed to lock offset."); }); let thread1 = thread::spawn(move || {
// Lock slice offset 1:
let mut guard = lock1.try_lock(1).expect("Failed to lock offset."); }); let thread2 = thread::spawn(move || {
// Lock slice offset 2:
let mut guard = lock2.try_lock(2).expect("Failed to lock offset."); }); thread0.join();
thread1.join();
thread2.join(); // Get the data that has been modified by the threads.
let data = Arc::tryunwrap(lock).expect("Thread is still using data.").intoinner(); assert_eq!(data,
vec![10, 20, 100, 200, 1000, 2000,
30, 40, 300, 400, 3000, 4000]);
``` The following new features might be candidates for future releases: Copyright (c) 2021 Michael Buesch \<m@bues.ch> Licensed under the Apache License version 2.0 or the MIT license, at
your option.Usage
{.toml}
[dependencies]
range-lock = "0.1"
RangeLock example usage
RepRangeLock example usage
// Read:
assert_eq!(guard[0][0], 1); // Cycle 0, Slice element 0
assert_eq!(guard[0][1], 2); // Cycle 0, Slice element 1
// let _ = guard[0][2]; // Would panic. Slice len is only 2.
assert_eq!(guard[1][0], 7); // Cycle 1, Slice element 0
assert_eq!(guard[1][1], 8); // Cycle 1, Slice element 1
// let _ = guard[2][0]; // Would panic: The data vec is only 2 repeat cycles long.
// Write:
guard[0][0] = 10; // Cycle 0, Slice element 0
guard[0][1] = 20; // Cycle 0, Slice element 1
// guard[0][2] = 42; // Would panic: Slice len is only 2.
guard[1][0] = 30; // Cycle 1, Slice element 0
guard[1][1] = 40; // Cycle 1, Slice element 1
// guard[2][0] = 42; // Would panic: The data vec is only 2 repeat cycles long.
guard[0][0] = 100; // Cycle 0, Slice element 0
guard[0][1] = 200; // Cycle 0, Slice element 1
guard[1][0] = 300; // Cycle 1, Slice element 0
guard[1][1] = 400; // Cycle 1, Slice element 1
guard[0][0] = 1000; // Cycle 0, Slice element 0
guard[0][1] = 2000; // Cycle 0, Slice element 1
guard[1][0] = 3000; // Cycle 1, Slice element 0
guard[1][1] = 4000; // Cycle 1, Slice element 1
TODOs for future releases
License