range-lock - Multithread range lock for Vec

https://bues.ch/

Provides multi-threaded access to a single Vec\

Usage

Add this to your Cargo.toml:

{.toml} [dependencies] range-lock = "0.1"

RangeLock example usage

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]); ```

RepRangeLock example usage

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.");

// 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.

});

let thread1 = thread::spawn(move || { // Lock slice offset 1: let mut guard = lock1.try_lock(1).expect("Failed to lock offset.");

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

});

let thread2 = thread::spawn(move || { // Lock slice offset 2: let mut guard = lock2.try_lock(2).expect("Failed to lock offset.");

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

});

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]); ```

TODOs for future releases

The following new features might be candidates for future releases:

License

Copyright (c) 2021 Michael Buesch \<m@bues.ch>

Licensed under the Apache License version 2.0 or the MIT license, at your option.