Theory and Design of PL (CS 538)
April 13, 2020
acct: Account
has balance 100acct.withdraw(75)
withdraw
with no interruptions
enum AcctMsg { Withdraw(i32), // ... other messages ... }
struct Account { balance: i32, msg: VecDeque<AcctMsg> };
impl Account {
fn send_withdraw(&mut self, amt: i32) {
self.msg.push_back(Withdraw(amt));
}
fn run_acct(&mut self) {
loop {
if let Some(Withdraw(amt)) = self.msg.pop_front() {
if self.balance < amt {
println!("Insufficient funds.");
} else { self.balance -= amt; }
} } } }
thread::spawn
fn main() {
let child = thread::spawn( || { // start child
for i in 1..10 {
println!("hi number {} from the spawned thread!", i);
// do some stuff, sleep for 10 seconds, ...
} });
// parent thread continues
for i in 1..5 {
println!("hi number {} from the main thread!", i);
// do some stuff, sleep for 10 seconds, ...
}
}
join
: wait for threads to finishfn main() {
let child = thread::spawn( || {
for i in 1..10 {
println!("hi number {} from the spawned thread!", i);
// do some stuff, sleep for 10 seconds, ...
} });
for i in 1..5 {
println!("hi number {} from the main thread!", i);
// do some stuff, sleep for 10 seconds, ...
}
child.join(); // wait for child to finish
}
let env_var: String = String::from("foo");
let child_one = thread::spawn( || {
// Not OK: env_var doesn't live long enough
let my_var = env_var;
println!("Child 1 printing: {}", my_var);
});
let child_two = thread::spawn( move || {
// OK: thread takes ownership of env_var
let my_var = env_var;
println!("Child 2 printing: {}", my_var);
});
let mut mut_var = String::new("foo");
let child_one = thread::spawn( move || {
// OK: thread takes ownership of mut_var
mut_var.push_str(" and bar");
});
let child_two = thread::spawn( move || {
// Not OK: can't move mut_var again!
mut_var.push_str(" and baz");
});
Rust compiler prevents data races!
env_var
Rc
to share ownershiplet env_var_old = Rc::new(String::new("foo"));
let env_var_one = Rc::clone(&env_var_old);
let env_var_two = Rc::clone(&env_var_old);
let child_one = thread::spawn(move || {
println!("Child 1 says: {}", env_var_one);
});
let child_two = thread::spawn(move || {
println!("Child 2 says: {}", env_var_two);
});
// String will live as long as one Rc is still alive
let env_var_old = Arc::new(String::new("foo"));
let env_var_one = Arc::clone(&env_var_old);
let env_var_two = Arc::clone(&env_var_old);
let child_one = thread::spawn(move || {
println!("Child 1 says: {}", env_var_one);
});
let child_two = thread::spawn(move || {
println!("Child 2 says: {}", env_var_two);
});
Rust compiler complains if you don’t use thread safe libraries with threads!
Send
trait: can be sent to another threadSync
trait: can be shared by multiple threadsRc
doesn’t implement Send
or Sync
: not safe!Arc
implements Send
and Sync
: thread safe!