Theory and Design of PL (CS 538)
April 15, 2020
new
: make a new mutexlock
: acquire lock, blocks if other thread has locklock()
will return Err(ptr)
.lock().unwrap()
ptr.into_inner
.Ownership to the rescue!
let my_mutex = Mutex::new(5);
{ // start new scope
// wait for the lock
let mut data_inside = my_mutex.lock().unwrap();
// holding the lock, write to value inside
*data_inside = 6;
// explicit unlock: std::mem::drop(data_inside);
} // or: scope ends, automatically unlocked here
// no longer holding lock here
let counter = Mutex::new(0);
let mut handles = vec![];
for i in 0..10 {
let handle = thread::spawn(move || { // move lock in
let mut num = counter.lock().unwrap(); // acquire lock
*num += 1;
});
handles.push(handle);
}
for handle in handles { handle.join(); }
Rc
to allow multiple owners of Mutexlet counter = Rc::new(Mutex::new(0)); // allow mutex to be shared
let mut handles = vec![];
for i in 0..10 {
let rc_count = Rc::clone(&counter); // get a ref to the mutex
let handle = thread::spawn(move || {
let mut num = rc_count.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles { handle.join(); }
Rc
is not Sync
”let counter = Arc::new(Mutex::new(0)); // use atomic Rc
let mut handles = vec![];
for i in 0..10 {
let rc_count = Arc::clone(&counter); // get a ref to the mutex
let handle = thread::spawn(move || {
let mut num = rc_count.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles { handle.join(); }
let acct = Account { balance: 100 };
let mutex = Mutex::new(acct); // wrap account in lock
let rc_mutex = Arc::new(mutex); // owner 1 of mutex
let rc_copy = Arc::clone(rc_mutex); // owner 2 of mutex
thread::spawn(move || {
let acct_ptr = rc_mutex.lock().unwrap(); // try to get lock
acct.try_withdraw(100); // got lock: try withdrawl
})
thread::spawn(move || {
let acct_ptr = rc_copy.lock().unwrap(); // try to get lock
acct.try_withdraw(100); // got lock: try withdrawl
})
std::sync::Condvar
docs…let p = Arc::new((Mutex::new(false), Condvar::new()));
let q = Arc::clone(&p);
// Spawn a new thread, which will signal when it starts
thread::spawn(move || {
let my_lock = q.0;
let my_cvar = q.1;
let mut started = my_lock.lock().unwrap(); // grab lock
*started = true;
// We notify the condvar that the value has changed.
my_cvar.notify_one();
}); // lock released here (started out of scope)
std::sync::Condvar
docs…let p = Arc::new((Mutex::new(false), Condvar::new()));
let q = Arc::clone(&p);
// Spawn a new thread, which will signal when it starts
thread::spawn(move || { ... });
let my_lock = p.0;
let my_cvar = p.1;
let mut started = my_lock.lock().unwrap(); // grab lock
// Spin: sleep-wake until flag is true
while !*started { started = my_cvar.wait(started).unwrap(); }
thread::spawn(move || {
// try to get lock
let acct_ptr = rc_acct2.lock().unwrap();
// got the lock, do deposit
acct_ptr.deposit(100);
// notify (all) waiters
rc_cvar2.notify_all();
});
mpsc::channel
mpsc::sync_channel
tx
for transmit, rx
for receivemove
to transfer ownership of endpointResult
type
unwrap
to stop program if errorrecv
waits for a message to be deliveredtry_recv
returns immediatelyResult
if there was no messageSend
can be sentfn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let val = String::from("hi");
tx.send(val).unwrap(); // transfer ownership
println!("val is {}", val); // Not OK: can't use val!
});
let received = rx.recv().unwrap(); // receive ownership
println!("Got: {}", received); // OK: can use val
}
let (tx, rx) = mpsc::channel();
let tx_copy = mpsc::Sender::clone(&tx); // copy transmit end
thread::spawn(move || { // make thread with tx
// ...
tx.send(val).unwrap();
});
thread::spawn(move || { // make thread with tx_copy
// ...
tx_copy.send(val).unwrap();
});
// receive messages
for received in rx { println!("Got: {}", received); }
std::sync::atomic
docs…fn main() {
let spinlock = Arc::new(AtomicUsize::new(1));
let spinlock_clone = spinlock.clone();
// child "has lock" ==> spinlock = 1
let thread = thread::spawn(move|| {
// child "releases lock"
spinlock_clone.store(0, Ordering::SeqCst);
});
// spin: wait for child to "release lock"
while spinlock.load(Ordering::SeqCst) != 0 {}
// continue onwards
}
std::sync::Barrier
docs…// Barrier that waits for 10 threads
let barrier = Arc::new(Barrier::new(10));
for i in 0..10 {
let c = barrier.clone();
thread::spawn(move|| {
println!("here");
c.wait();
println!("there");
}));
}
std::sync::RwLock
docs…Arc