Lecture Note 5
Review
//api.rs
pub fn lock(&self) -> LockGuard<L, T> {
}
pub struct LockGuard<'s, L: RawLock, T> {
lock: &'s Lock<L, T>,
token: ManuallyDrop<L::Token>
}
// lifetime 's ensures that drop(g) should preceed drop(d)
impl<'s, L: RawLock, T> Deref for LockGuard<'s, L, T> {
fn deref(&self) -> &self::Target {
unsafe {
self.lock.get_unchecked();
}
}
}
impl<'s, L: RawLock, T> DerefMut for LockGuard<'s, L, T> {
fn deref_mut(&mut self) -> &mut self::Target {
unsafe {
self.lock.get_mut_unchecked();
}
}
}
g = d.lock();
// critical section
drop(g);
g = d.lock();
*g = 42;
bad = &mut *g;
drop(g);
*bad = 666; // g's lifetime ended!
drop(d);
deref taget shall not outlive guard
let d_guard = data.lock();
let d_ref = d_uard.deref();
drop(d_guard)
*d_ref // illegal
Safe API for lock based concurrency
Thread, channel, (rw) lock, mutex, etc.
use std::thread;
let thread_join_handle = thread::spanw(move || {
todo!();
});
thread_join_handle.join(); wait until the thred ends
forking process vs spawning thread
-
similar concepts, but different internals; NOT COVERED IN CLASS
-
Allocating Thread Local STorage
id = tid();
addr = TLS[id]; // stored in the heap
// threads do not share this local storage
spawn<F, T>(self, f: F)
where
F: FnOnce() -> T,
F: Send + 'static, // closure called inside spawn should live long
T: Send + 'static, //
//e.g.
let v = 42;
let r = &v;
spawn(|| {
*r; // error: we don't know whether r is dangling or not:
// what if v is released?
})
why FnOnce?
let v = vec![1,2,3];
|| {
v.into_iter().sum(); // consumes v: calling multiple times is not allowed
}
- scoped thread: restricting thread's lifetime within a scope
spawn<F, T>(&'scope self, f: F) -> ScopedJoinHandle<'scope, T>
where
F: FnOnce() -> T + Send + 'scope,
T: Send + 'scope, //
Anonymous functon is passed (wrapped) into a struct having the information of surroundig scope