Struct happylock::LockCollection
source · pub struct LockCollection<L> { /* private fields */ }Expand description
A type which can be locked.
This could be a tuple of Lockable types, an array, or a Vec. But it
can be safely locked without causing a deadlock. To do this, it is very
important that no duplicate locks are included within.
Implementations§
source§impl<'a, L: OwnedLockable<'a>> LockCollection<L>
impl<'a, L: OwnedLockable<'a>> LockCollection<L>
sourcepub const fn new(data: L) -> Self
pub const fn new(data: L) -> Self
Creates a new collection of owned locks.
Because the locks are owned, there’s no need to do any checks for duplicate values.
§Examples
use happylock::{LockCollection, Mutex};
let lock = LockCollection::new((Mutex::new(0), Mutex::new("")));sourcepub const fn new_ref(data: &L) -> LockCollection<&L>
pub const fn new_ref(data: &L) -> LockCollection<&L>
Creates a new collection of owned locks.
Because the locks are owned, there’s no need to do any checks for duplicate values.
§Examples
use happylock::{LockCollection, Mutex};
let data = (Mutex::new(0), Mutex::new(""));
let lock = LockCollection::new_ref(&data);Examples found in repository?
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
fn main() {
let mut threads = Vec::new();
for _ in 0..N {
let th = thread::spawn(move || {
let key = ThreadKey::get().unwrap();
let lock = LockCollection::new_ref(&DATA);
let mut guard = lock.lock(key);
*guard.1 = (100 - *guard.0).to_string();
*guard.0 += 1;
});
threads.push(th);
}
for th in threads {
_ = th.join();
}
let key = ThreadKey::get().unwrap();
let data = LockCollection::new_ref(&DATA);
let data = data.lock(key);
println!("{}", *data.0);
println!("{}", *data.1);
}More examples
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
fn main() {
let mut threads = Vec::new();
for _ in 0..N {
let th = thread::spawn(move || {
let mut key = ThreadKey::get().unwrap();
loop {
let mut data = Vec::new();
for _ in 0..3 {
let rand = random(&mut key);
data.push(&DATA[rand % 6]);
}
let Some(lock) = LockCollection::try_new(data) else {
continue;
};
let mut guard = lock.lock(&mut key);
*guard[0] += *guard[1];
*guard[1] += *guard[2];
*guard[2] += *guard[0];
return;
}
});
threads.push(th);
}
for th in threads {
_ = th.join();
}
let key = ThreadKey::get().unwrap();
let data = LockCollection::new_ref(&DATA);
let data = data.lock(key);
for val in &*data {
println!("{}", **val);
}
}source§impl<L> LockCollection<L>
impl<L> LockCollection<L>
sourcepub const unsafe fn new_unchecked(data: L) -> Self
pub const unsafe fn new_unchecked(data: L) -> Self
Creates a new collections of locks.
§Safety
This results in undefined behavior if any locks are presented twice within this collection.
§Examples
use happylock::{LockCollection, Mutex};
let data1 = Mutex::new(0);
let data2 = Mutex::new("");
// safety: data1 and data2 refer to distinct mutexes
let lock = unsafe { LockCollection::new_unchecked((&data1, &data2)) };Examples found in repository?
48 49 50 51 52 53 54 55 56 57 58 59 60
fn cycle(&self) {
let key = ThreadKey::get().unwrap();
thread::sleep(Duration::from_secs(1));
// safety: no philosopher asks for the same fork twice
let forks =
unsafe { LockCollection::new_unchecked([&FORKS[self.left], &FORKS[self.right]]) };
let forks = forks.lock(key);
println!("{} is eating...", self.name);
thread::sleep(Duration::from_secs(1));
println!("{} is done eating", self.name);
drop(forks);
}source§impl<'a, L: Lockable<'a>> LockCollection<L>
impl<'a, L: Lockable<'a>> LockCollection<L>
sourcepub fn try_new(data: L) -> Option<Self>
pub fn try_new(data: L) -> Option<Self>
Creates a new collection of locks.
This returns None if any locks are found twice in the given
collection.
§Performance
This does a check at runtime to make sure that the collection contains
no two copies of the same lock. This is an O(n^2) operation. Prefer
LockCollection::new or LockCollection::new_ref instead.
§Examples
use happylock::{LockCollection, Mutex};
let data1 = Mutex::new(0);
let data2 = Mutex::new("");
// data1 and data2 refer to distinct mutexes, so this won't panic
let lock = LockCollection::try_new((&data1, &data2)).unwrap();Examples found in repository?
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
fn main() {
let mut threads = Vec::new();
for _ in 0..N {
let th = thread::spawn(move || {
let mut key = ThreadKey::get().unwrap();
loop {
let mut data = Vec::new();
for _ in 0..3 {
let rand = random(&mut key);
data.push(&DATA[rand % 6]);
}
let Some(lock) = LockCollection::try_new(data) else {
continue;
};
let mut guard = lock.lock(&mut key);
*guard[0] += *guard[1];
*guard[1] += *guard[2];
*guard[2] += *guard[0];
return;
}
});
threads.push(th);
}
for th in threads {
_ = th.join();
}
let key = ThreadKey::get().unwrap();
let data = LockCollection::new_ref(&DATA);
let data = data.lock(key);
for val in &*data {
println!("{}", **val);
}
}sourcepub fn lock<'key: 'a, Key: Keyable + 'key>(
&'a self,
key: Key
) -> LockGuard<'a, 'key, L, Key>
pub fn lock<'key: 'a, Key: Keyable + 'key>( &'a self, key: Key ) -> LockGuard<'a, 'key, L, Key>
Locks the collection
This function returns a guard that can be used to access the underlying data. When the guard is dropped, the locks in the collection are also dropped.
§Examples
use happylock::{LockCollection, Mutex, ThreadKey};
let key = ThreadKey::get().unwrap();
let lock = LockCollection::new((Mutex::new(0), Mutex::new("")));
let mut guard = lock.lock(key);
*guard.0 += 1;
*guard.1 = "1";Examples found in repository?
48 49 50 51 52 53 54 55 56 57 58 59 60
fn cycle(&self) {
let key = ThreadKey::get().unwrap();
thread::sleep(Duration::from_secs(1));
// safety: no philosopher asks for the same fork twice
let forks =
unsafe { LockCollection::new_unchecked([&FORKS[self.left], &FORKS[self.right]]) };
let forks = forks.lock(key);
println!("{} is eating...", self.name);
thread::sleep(Duration::from_secs(1));
println!("{} is done eating", self.name);
drop(forks);
}More examples
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
fn main() {
let mut threads = Vec::new();
for _ in 0..N {
let th = thread::spawn(move || {
let key = ThreadKey::get().unwrap();
let lock = LockCollection::new_ref(&DATA);
let mut guard = lock.lock(key);
*guard.1 = (100 - *guard.0).to_string();
*guard.0 += 1;
});
threads.push(th);
}
for th in threads {
_ = th.join();
}
let key = ThreadKey::get().unwrap();
let data = LockCollection::new_ref(&DATA);
let data = data.lock(key);
println!("{}", *data.0);
println!("{}", *data.1);
}28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
fn main() {
let mut threads = Vec::new();
for _ in 0..N {
let th = thread::spawn(move || {
let mut key = ThreadKey::get().unwrap();
loop {
let mut data = Vec::new();
for _ in 0..3 {
let rand = random(&mut key);
data.push(&DATA[rand % 6]);
}
let Some(lock) = LockCollection::try_new(data) else {
continue;
};
let mut guard = lock.lock(&mut key);
*guard[0] += *guard[1];
*guard[1] += *guard[2];
*guard[2] += *guard[0];
return;
}
});
threads.push(th);
}
for th in threads {
_ = th.join();
}
let key = ThreadKey::get().unwrap();
let data = LockCollection::new_ref(&DATA);
let data = data.lock(key);
for val in &*data {
println!("{}", **val);
}
}sourcepub fn try_lock<'key: 'a, Key: Keyable + 'key>(
&'a self,
key: Key
) -> Option<LockGuard<'a, 'key, L, Key>>
pub fn try_lock<'key: 'a, Key: Keyable + 'key>( &'a self, key: Key ) -> Option<LockGuard<'a, 'key, L, Key>>
Attempts to lock the without blocking.
If successful, this method returns a guard that can be used to access
the data, and unlocks the data when it is dropped. Otherwise, None is
returned.
§Examples
use happylock::{LockCollection, Mutex, ThreadKey};
let key = ThreadKey::get().unwrap();
let lock = LockCollection::new((Mutex::new(0), Mutex::new("")));
match lock.try_lock(key) {
Some(mut guard) => {
*guard.0 += 1;
*guard.1 = "1";
},
None => unreachable!(),
};
sourcepub fn unlock<'key: 'a, Key: Keyable + 'key>(
guard: LockGuard<'a, 'key, L, Key>
) -> Key
pub fn unlock<'key: 'a, Key: Keyable + 'key>( guard: LockGuard<'a, 'key, L, Key> ) -> Key
Unlocks the underlying lockable data type, returning the key that’s associated with it.
§Examples
use happylock::{LockCollection, Mutex, ThreadKey};
let key = ThreadKey::get().unwrap();
let lock = LockCollection::new((Mutex::new(0), Mutex::new("")));
let mut guard = lock.lock(key);
*guard.0 += 1;
*guard.1 = "1";
let key = LockCollection::unlock(guard);source§impl<'a, L: 'a> LockCollection<L>where
&'a L: IntoIterator,
impl<'a, L: 'a> LockCollection<L>where
&'a L: IntoIterator,
sourcepub fn iter(&'a self) -> <&'a L as IntoIterator>::IntoIter
pub fn iter(&'a self) -> <&'a L as IntoIterator>::IntoIter
Returns an iterator over references to each value in the collection.
source§impl<'a, L: 'a> LockCollection<L>where
&'a mut L: IntoIterator,
impl<'a, L: 'a> LockCollection<L>where
&'a mut L: IntoIterator,
sourcepub fn iter_mut(&'a mut self) -> <&'a mut L as IntoIterator>::IntoIter
pub fn iter_mut(&'a mut self) -> <&'a mut L as IntoIterator>::IntoIter
Returns an iterator over mutable references to each value in the collection.
Trait Implementations§
source§impl<'a, L: Lockable<'a>> AsMut<L> for LockCollection<L>
impl<'a, L: Lockable<'a>> AsMut<L> for LockCollection<L>
source§impl<'a, L: Lockable<'a>> AsMut<LockCollection<L>> for LockCollection<L>
impl<'a, L: Lockable<'a>> AsMut<LockCollection<L>> for LockCollection<L>
source§impl<'a, L: Lockable<'a>> AsRef<L> for LockCollection<L>
impl<'a, L: Lockable<'a>> AsRef<L> for LockCollection<L>
source§impl<'a, L: Lockable<'a>> AsRef<LockCollection<L>> for LockCollection<L>
impl<'a, L: Lockable<'a>> AsRef<LockCollection<L>> for LockCollection<L>
source§impl<L: Clone> Clone for LockCollection<L>
impl<L: Clone> Clone for LockCollection<L>
source§fn clone(&self) -> LockCollection<L>
fn clone(&self) -> LockCollection<L>
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moresource§impl<L: Debug> Debug for LockCollection<L>
impl<L: Debug> Debug for LockCollection<L>
source§impl<'a, E: OwnedLockable<'a> + Extend<L>, L: OwnedLockable<'a>> Extend<L> for LockCollection<E>
impl<'a, E: OwnedLockable<'a> + Extend<L>, L: OwnedLockable<'a>> Extend<L> for LockCollection<E>
source§fn extend<T: IntoIterator<Item = L>>(&mut self, iter: T)
fn extend<T: IntoIterator<Item = L>>(&mut self, iter: T)
source§fn extend_one(&mut self, item: A)
fn extend_one(&mut self, item: A)
extend_one)source§fn extend_reserve(&mut self, additional: usize)
fn extend_reserve(&mut self, additional: usize)
extend_one)