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>

source

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("")));
source

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?
examples/double_mutex.rs (line 14)
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
Hide additional examples
examples/list.rs (line 59)
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>

source

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?
examples/dining_philosophers.rs (line 54)
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>

source

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?
examples/list.rs (line 40)
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

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?
examples/dining_philosophers.rs (line 55)
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
Hide additional examples
examples/double_mutex.rs (line 15)
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);
}
examples/list.rs (line 43)
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

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!(),
};
source

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>

source

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>

source

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>

source§

fn as_mut(&mut self) -> &mut L

Converts this type into a mutable reference of the (usually inferred) input type.
source§

impl<'a, L: Lockable<'a>> AsMut<LockCollection<L>> for LockCollection<L>

source§

fn as_mut(&mut self) -> &mut Self

Converts this type into a mutable reference of the (usually inferred) input type.
source§

impl<'a, L: Lockable<'a>> AsRef<L> for LockCollection<L>

source§

fn as_ref(&self) -> &L

Converts this type into a shared reference of the (usually inferred) input type.
source§

impl<'a, L: Lockable<'a>> AsRef<LockCollection<L>> for LockCollection<L>

source§

fn as_ref(&self) -> &Self

Converts this type into a shared reference of the (usually inferred) input type.
source§

impl<L: Clone> Clone for LockCollection<L>

source§

fn clone(&self) -> LockCollection<L>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<L: Debug> Debug for LockCollection<L>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

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)

Extends a collection with the contents of an iterator. Read more
source§

fn extend_one(&mut self, item: A)

🔬This is a nightly-only experimental API. (extend_one)
Extends a collection with exactly one element.
source§

fn extend_reserve(&mut self, additional: usize)

🔬This is a nightly-only experimental API. (extend_one)
Reserves capacity in a collection for the given number of additional elements. Read more
source§

impl<'a, L: OwnedLockable<'a>> From<L> for LockCollection<L>

source§

fn from(value: L) -> Self

Converts to this type from the input type.
source§

impl<'a, L: OwnedLockable<'a>, I: FromIterator<L> + OwnedLockable<'a>> FromIterator<L> for LockCollection<I>

source§

fn from_iter<T: IntoIterator<Item = L>>(iter: T) -> Self

Creates a value from an iterator. Read more
source§

impl<'a, L> IntoIterator for &'a LockCollection<L>

§

type Item = <&'a L as IntoIterator>::Item

The type of the elements being iterated over.
§

type IntoIter = <&'a L as IntoIterator>::IntoIter

Which kind of iterator are we turning this into?
source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
source§

impl<'a, L> IntoIterator for &'a mut LockCollection<L>

§

type Item = <&'a mut L as IntoIterator>::Item

The type of the elements being iterated over.
§

type IntoIter = <&'a mut L as IntoIterator>::IntoIter

Which kind of iterator are we turning this into?
source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
source§

impl<L: IntoIterator> IntoIterator for LockCollection<L>

§

type Item = <L as IntoIterator>::Item

The type of the elements being iterated over.
§

type IntoIter = <L as IntoIterator>::IntoIter

Which kind of iterator are we turning this into?
source§

fn into_iter(self) -> Self::IntoIter

Creates an iterator from a value. Read more
source§

impl<L: Copy> Copy for LockCollection<L>

Auto Trait Implementations§

§

impl<L> Freeze for LockCollection<L>
where L: Freeze,

§

impl<L> RefUnwindSafe for LockCollection<L>
where L: RefUnwindSafe,

§

impl<L> Send for LockCollection<L>
where L: Send,

§

impl<L> Sync for LockCollection<L>
where L: Sync,

§

impl<L> Unpin for LockCollection<L>
where L: Unpin,

§

impl<L> UnwindSafe for LockCollection<L>
where L: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.