Expand description
This crate provides a general optimistic lock.
§Description
In actual projects, there are some lock-free data structures, especially database-related ones such as BwTree
, Split-Ordered List
(also known as Lock Free HashTable) when there are many write conflicts.
The performance loss is very serious, and sometimes it is not as good as the brainless Mutex. However, the performance of the brainless Mutex is often very bad under normal circumstances, so is there an intermediate form that can solve this problem?
This is the intermediate form. So this can be used everywhere as a general lock, and the performance is satisfactory.
§Simple example for read
use optimistic_lock_coupling::{OptimisticLockCoupling, OptimisticLockCouplingErrorType};
#[inline(always)]
fn read_txn(lock: &OptimisticLockCoupling<i32>) -> Result<(), OptimisticLockCouplingErrorType> {
// acquire the read lock
let read_guard = lock.read()?;
// do your stuff
println!("status: {}", read_guard);
println!("\tmy operations: {} + 1 = {}", *read_guard, *read_guard + 1);
// remember to sync before drop
let res = read_guard.try_sync();
println!("safely synced");
res
}
fn main() {
let lock = OptimisticLockCoupling::new(1);
// retry steps
'retry: loop{
// function call
let res = read_txn(&lock);
// before retry logics
if res.is_err() {
continue 'retry;
}else{
break 'retry;
}
}
}
or in a much easy way~
fn main(){
let lock = OptimisticLockCoupling::new(1);
lock.read_txn(
// very important!
#[inline(always)]
|guard| {
println!("{}", guard);
Ok(())
},
)
.unwrap();
}
§Thread-safety example
will create a read thread and a write thread both holding the same lock.
use optimistic_lock_coupling::*;
fn main() {
let i = 10000;
static mut lock: Option<OptimisticLockCoupling<i32>> = None;
unsafe { lock = Some(OptimisticLockCoupling::from(0)) };
let write_fn = move || unsafe {
for _i in 0..i {
// std::thread::sleep_ms(10);
loop {
match lock.as_ref().unwrap().write() {
Ok(mut guard) => {
*guard += 1;
break;
}
Err(_err) => {
continue;
}
}
}
}
};
let read_fn = move || unsafe {
for _i in 0..i {
while let Ok(_) = lock.as_ref().unwrap().read_txn(
#[inline(always)]
|guard| {
println!("{}", guard);
Ok(())
},
) {
break;
}
}
};
use std::thread::spawn;
let thread1 = spawn(write_fn);
let thread2 = spawn(read_fn);
let _ = thread1.join();
let _ = thread2.join();
unsafe { assert_eq!(*(lock.as_ref().unwrap().write().unwrap()), i) }
}
Structs§
- Optimistic
Lock Coupling - Our data structure, the usage is ‘pretty much’ same as RwLock
- Optimistic
Lock Coupling Read Guard - Usage:
after getting the guard you can do what ever you want with Deref
but after usage you MUST call
try_sync
if fails you must redo the hole function or other sync method to ensure the data you read is correct. - Optimistic
Lock Coupling Write Guard - Only one instance because the data is locked
implemented
Deref
andDerefMut
release the lock on drop
Enums§
- Optimistic
Lock Coupling Error Type - Error types
Type Aliases§
- Optimistic
Lock Coupling Result - Result type~