SlideShare a Scribd company logo
Aaron Turon	

Mozilla Research
InfoQ.com: News & Community Site
• 750,000 unique visitors/month
• Published in 4 languages (English, Chinese, Japanese and Brazilian
Portuguese)
• Post content from our QCon conferences
• News 15-20 / week
• Articles 3-4 / week
• Presentations (videos) 12-15 / week
• Interviews 2-3 / week
• Books 1 / month
Watch the video with slide
synchronization on InfoQ.com!
http://www.infoq.com/presentations
/rust-thread-safety
Purpose of QCon
- to empower software development by facilitating the spread of
knowledge and innovation
Strategy
- practitioner-driven conference designed for YOU: influencers of
change and innovation in your teams
- speakers and topics driving the evolution and innovation
- connecting and catalyzing the influencers and innovators
Highlights
- attended by more than 12,000 delegates since 2007
- held in 9 cities worldwide
Presented at QCon San Francisco
www.qconsf.com
Rust is a systems programming language
that runs blazingly fast, prevents nearly all
segfaults, and guarantees thread safety. 	

- https://www.rust-lang.org/
Safety
Control
C C++
Go
Java
Haskell
Scala
“Low-level”
Conventional wisdom
The Essence of Rust
Low-level == Unsafe
+ Safe
Why Rust?
- You’re already doing systems programming, 

want safety or expressiveness.	

!
- You wish you could do some systems work	

- Maybe as an embedded piece in your

Java, Python, JS, Ruby, …
Why Mozilla?
Browsers need control.
Browsers need safety.
Servo: Next-generation
browser built in Rust.
Rust: New language for 	

safe systems programming.
What is control?
void example() {
vector<string> vector;
…
auto& elem = vector[0];
…
}
string[0]
…elem
vector
data
length
capacity
[0]
[n]
[…]
…
‘H’
…
‘e’
Stack and inline layout.
Interior references
Deterministic destruction
Stack Heap
C++
Zero-cost abstraction
Ability to define abstractions that	

optimize away to nothing.
vector data
length
cap.
[0]
[…]
data cap.
‘H’
‘e’
[…]
Not just memory layout:	

- Static dispatch	

- Template expansion	

- … Java
What is safety?
void example() {
vector<string> vector;
…
auto& elem = vector[0];
vector.push_back(some_string);
cout << elem;
}
vector
data
length
capacity
[0]
…
[0]
[1]
elem
Aliasing: more than	

one pointer to same	

memory.
Dangling pointer: pointer	

to freed memory.
C++
Mutating the vector	

freed old contents.
What about GC?
No control.
Requires a runtime.
Insufficient to prevent related problems:	

iterator invalidation, data races, many others.
Ownership & Borrowing
Memory	

safety
Data-race	

freedom	

(and more)
No need for	

a runtime
GCC++
… Plus lots of goodies
- Pattern matching	

- Traits	

- “Smart” pointers	

- Metaprogramming	

- Package management (think Bundler)
TL;DR: Rust is a modern language
Ownership
!
n. The act, state, or right of possessing something.
Ownership (T)
Aliasing Mutation
vec
data
length
capacity
vec
data
length
capacity
1
2
fn give() {
let mut vec = Vec::new();
vec.push(1);
vec.push(2);
take(vec);
…
}
fn take(vec: Vec<int>) {
// …
}
!
!
!
Take ownership	

of aVec<int>
fn give() {
let mut vec = Vec::new();
vec.push(1);
vec.push(2);
take(vec);
…
}
vec.push(2);
Compiler enforces moves
fn take(vec: Vec<int>) {
// …
}
!
!
!Error: vec has been moved
Prevents:	

- use after free	

- double moves	

- …
Borrow
!
v. To receive something with the promise of returning it.
Shared borrow (&T)
Aliasing Mutation
Mutable borrow (&mut T)
Aliasing Mutation
fn lender() {
let mut vec = Vec::new();
vec.push(1);
vec.push(2);
use(&vec);
…
}
fn use(vec: &Vec<int>) {
// …
}
!
!
!
1
2vec
data
length
capacity
vec
“Shared reference	

toVec<int>”
Loan out vec
fn use(vec: &Vec<int>) {
vec.push(3);
vec[1] += 2;
}
Shared references are immutable:
Error: cannot mutate shared reference
* Actually: mutation only in controlled circumstances
*
Aliasing Mutation
fn push_all(from: &Vec<int>, to: &mut Vec<int>) {
for elem in from {
to.push(*elem);
}
}
Mutable references
mutable reference to Vec<int>
push() is legal
1
2
3
from
to
elem
1
…
fn push_all(from: &Vec<int>, to: &mut Vec<int>) {
for elem in from {
to.push(*elem);
}
}
Mutable references
What if from and to are equal?
1
2
3
from
to
elem
1
2
3
…
1
fn push_all(from: &Vec<int>, to: &mut Vec<int>) {
for elem in from {
to.push(*elem);
}
} dangling pointer
fn push_all(from: &Vec<int>, to: &mut Vec<int>) {…}
!
fn caller() {
let mut vec = …;
push_all(&vec, &mut vec);
}
shared reference
Error: cannot have both shared and
mutable reference at same time
A &mut T is the only way to access	

the memory it points at
{
let mut vec = Vec::new();
…
for i in 0 .. vec.len() {
let elem: &int = &vec[i];
…
vec.push(…);
}
…
vec.push(…);
}
Borrows restrict access to
the original path for their
duration.
Error: vec[i] is borrowed,
cannot mutate
OK. loan expired.
&
&mut
no writes, no moves
no access at all
Concurrency
!
n. several computations executing simultaneously, and
potentially interacting with each other.
Rust’s vision for concurrency
Originally:	

!
Now:
only isolated message passing
libraries for many paradigms,	

using ownership to avoid footguns,	

guaranteeing no data races
Data race
Two unsynchronized threads	

accessing same data
where at least one writes.
✎
✎
Aliasing
Mutation
No ordering
Data race
Sound familiar?
No data races =	

No accidentally-shared state.	

!
All sharing is explicit!
*some_value = 5;
return *some_value == 5; // ALWAYS true
Messaging
(ownership)
data
length
capacity
data
length
capacity
move || {
let m = Vec::new();
…
tx.send(m);
}
rx
tx
tx
m
fn parent() {
let (tx, rx) = channel();
spawn(move || {…});
let m = rx.recv();
}
Locked mutable access
(ownership, borrowing)
✎
✎
fn sync_inc(mutex: &Mutex<int>) {
let mut data = mutex.lock();
*data += 1;
}
Destructor releases lock
Yields a mutable reference to data
Destructor runs here, releasing lock
Disjoint, scoped access
(borrowing)
✎
✎
fn qsort(vec: &mut [int]) {
if vec.len() <= 1 { return; }
let pivot = vec[random(vec.len())];
let mid = vec.partition(vec, pivot);
let (less, greater) = vec.split_at_mut(mid);
qsort(less);
qsort(greater);
}
[0] [1] [2] [3] […] [n]
let vec: &mut [int] = …;
less greater
fn split_at_mut(&mut self, mid: usize)
-> (&mut [T], & mut [T])
[0] [1] [2] [3] […] [n]
let vec: &mut [int] = …;
less greater
fn parallel_qsort(vec: &mut [int]) {
if vec.len() <= 1 { return; }
let pivot = vec[random(vec.len())];
let mid = vec.partition(vec, pivot);
let (less, greater) = vec.split_at_mut(mid);
parallel::join(
|| parallel_qsort(less),
|| parallel_qsort(greater)
);
}
Arc<Vec<int>>: Send
Rc<Vec<int>> : !Send
fn send<T: Send>(&self, t: T)
Only “sendable” types
Static checking for thread safety
And beyond…
Concurrency is an area of active development.	

!
Either already have or have plans for:	

- Atomic primitives	

- Non-blocking queues	

- Concurrent hashtables	

- Lightweight thread pools	

- Futures	

- CILK-style fork-join concurrency	

- etc.
Always data-race free
Unsafe
!
adj. not safe; hazardous
Safe abstractions
unsafe {
…
}
Useful for:	

	

 Bending mutation/aliasing rules (split_at_mut)	

	

 Interfacing with C code
Trust me.
fn something_safe(…) {
!
!
!
!
}
Validates input, etc.
Ownership enables safe abstraction boundaries.
Community
!
n. A feeling of fellowship with others sharing similar goals.
“The Rust community seems to be
populated entirely by human beings.
I have no idea how this was done.”	

— Jamie Brandon
It takes a village…
Community focus from the start:	

	

 Rust 1.0 had > 1,000 contributors	

	

 Welcoming, pragmatic culture	

!
Developed “in the open”	

	

 Much iteration;	

humility is key!	

!
Clear leadership	

	

 Mix of academic and engineering backgrounds	

	

 “Keepers of the vision”
Rust: Unlocking Systems Programming
Memory safety	

Concurrency	

Abstraction	

Stability
without
garbage collection	

data races	

overhead	

stagnation
Hack without fear!
Articulating the vision
Watch the video with slide synchronization on
InfoQ.com!
http://www.infoq.com/presentations/rust-
thread-safety

More Related Content

Rust: Unlocking Systems Programming

  • 2. InfoQ.com: News & Community Site • 750,000 unique visitors/month • Published in 4 languages (English, Chinese, Japanese and Brazilian Portuguese) • Post content from our QCon conferences • News 15-20 / week • Articles 3-4 / week • Presentations (videos) 12-15 / week • Interviews 2-3 / week • Books 1 / month Watch the video with slide synchronization on InfoQ.com! http://www.infoq.com/presentations /rust-thread-safety
  • 3. Purpose of QCon - to empower software development by facilitating the spread of knowledge and innovation Strategy - practitioner-driven conference designed for YOU: influencers of change and innovation in your teams - speakers and topics driving the evolution and innovation - connecting and catalyzing the influencers and innovators Highlights - attended by more than 12,000 delegates since 2007 - held in 9 cities worldwide Presented at QCon San Francisco www.qconsf.com
  • 4. Rust is a systems programming language that runs blazingly fast, prevents nearly all segfaults, and guarantees thread safety. - https://www.rust-lang.org/
  • 6. Conventional wisdom The Essence of Rust Low-level == Unsafe + Safe
  • 7. Why Rust? - You’re already doing systems programming, 
 want safety or expressiveness. ! - You wish you could do some systems work - Maybe as an embedded piece in your
 Java, Python, JS, Ruby, …
  • 8. Why Mozilla? Browsers need control. Browsers need safety. Servo: Next-generation browser built in Rust. Rust: New language for safe systems programming.
  • 9. What is control? void example() { vector<string> vector; … auto& elem = vector[0]; … } string[0] …elem vector data length capacity [0] [n] […] … ‘H’ … ‘e’ Stack and inline layout. Interior references Deterministic destruction Stack Heap C++
  • 10. Zero-cost abstraction Ability to define abstractions that optimize away to nothing. vector data length cap. [0] […] data cap. ‘H’ ‘e’ […] Not just memory layout: - Static dispatch - Template expansion - … Java
  • 11. What is safety? void example() { vector<string> vector; … auto& elem = vector[0]; vector.push_back(some_string); cout << elem; } vector data length capacity [0] … [0] [1] elem Aliasing: more than one pointer to same memory. Dangling pointer: pointer to freed memory. C++ Mutating the vector freed old contents.
  • 12. What about GC? No control. Requires a runtime. Insufficient to prevent related problems: iterator invalidation, data races, many others.
  • 14. … Plus lots of goodies - Pattern matching - Traits - “Smart” pointers - Metaprogramming - Package management (think Bundler) TL;DR: Rust is a modern language
  • 15. Ownership ! n. The act, state, or right of possessing something.
  • 17. vec data length capacity vec data length capacity 1 2 fn give() { let mut vec = Vec::new(); vec.push(1); vec.push(2); take(vec); … } fn take(vec: Vec<int>) { // … } ! ! ! Take ownership of aVec<int>
  • 18. fn give() { let mut vec = Vec::new(); vec.push(1); vec.push(2); take(vec); … } vec.push(2); Compiler enforces moves fn take(vec: Vec<int>) { // … } ! ! !Error: vec has been moved Prevents: - use after free - double moves - …
  • 19. Borrow ! v. To receive something with the promise of returning it.
  • 21. Mutable borrow (&mut T) Aliasing Mutation
  • 22. fn lender() { let mut vec = Vec::new(); vec.push(1); vec.push(2); use(&vec); … } fn use(vec: &Vec<int>) { // … } ! ! ! 1 2vec data length capacity vec “Shared reference toVec<int>” Loan out vec
  • 23. fn use(vec: &Vec<int>) { vec.push(3); vec[1] += 2; } Shared references are immutable: Error: cannot mutate shared reference * Actually: mutation only in controlled circumstances * Aliasing Mutation
  • 24. fn push_all(from: &Vec<int>, to: &mut Vec<int>) { for elem in from { to.push(*elem); } } Mutable references mutable reference to Vec<int> push() is legal
  • 25. 1 2 3 from to elem 1 … fn push_all(from: &Vec<int>, to: &mut Vec<int>) { for elem in from { to.push(*elem); } } Mutable references
  • 26. What if from and to are equal? 1 2 3 from to elem 1 2 3 … 1 fn push_all(from: &Vec<int>, to: &mut Vec<int>) { for elem in from { to.push(*elem); } } dangling pointer
  • 27. fn push_all(from: &Vec<int>, to: &mut Vec<int>) {…} ! fn caller() { let mut vec = …; push_all(&vec, &mut vec); } shared reference Error: cannot have both shared and mutable reference at same time A &mut T is the only way to access the memory it points at
  • 28. { let mut vec = Vec::new(); … for i in 0 .. vec.len() { let elem: &int = &vec[i]; … vec.push(…); } … vec.push(…); } Borrows restrict access to the original path for their duration. Error: vec[i] is borrowed, cannot mutate OK. loan expired. & &mut no writes, no moves no access at all
  • 29. Concurrency ! n. several computations executing simultaneously, and potentially interacting with each other.
  • 30. Rust’s vision for concurrency Originally: ! Now: only isolated message passing libraries for many paradigms, using ownership to avoid footguns, guaranteeing no data races
  • 31. Data race Two unsynchronized threads accessing same data where at least one writes. ✎ ✎
  • 33. No data races = No accidentally-shared state. ! All sharing is explicit! *some_value = 5; return *some_value == 5; // ALWAYS true
  • 35. data length capacity data length capacity move || { let m = Vec::new(); … tx.send(m); } rx tx tx m fn parent() { let (tx, rx) = channel(); spawn(move || {…}); let m = rx.recv(); }
  • 36. Locked mutable access (ownership, borrowing) ✎ ✎
  • 37. fn sync_inc(mutex: &Mutex<int>) { let mut data = mutex.lock(); *data += 1; } Destructor releases lock Yields a mutable reference to data Destructor runs here, releasing lock
  • 39. fn qsort(vec: &mut [int]) { if vec.len() <= 1 { return; } let pivot = vec[random(vec.len())]; let mid = vec.partition(vec, pivot); let (less, greater) = vec.split_at_mut(mid); qsort(less); qsort(greater); } [0] [1] [2] [3] […] [n] let vec: &mut [int] = …; less greater
  • 40. fn split_at_mut(&mut self, mid: usize) -> (&mut [T], & mut [T])
  • 41. [0] [1] [2] [3] […] [n] let vec: &mut [int] = …; less greater fn parallel_qsort(vec: &mut [int]) { if vec.len() <= 1 { return; } let pivot = vec[random(vec.len())]; let mid = vec.partition(vec, pivot); let (less, greater) = vec.split_at_mut(mid); parallel::join( || parallel_qsort(less), || parallel_qsort(greater) ); }
  • 42. Arc<Vec<int>>: Send Rc<Vec<int>> : !Send fn send<T: Send>(&self, t: T) Only “sendable” types Static checking for thread safety
  • 43. And beyond… Concurrency is an area of active development. ! Either already have or have plans for: - Atomic primitives - Non-blocking queues - Concurrent hashtables - Lightweight thread pools - Futures - CILK-style fork-join concurrency - etc. Always data-race free
  • 45. Safe abstractions unsafe { … } Useful for: Bending mutation/aliasing rules (split_at_mut) Interfacing with C code Trust me. fn something_safe(…) { ! ! ! ! } Validates input, etc. Ownership enables safe abstraction boundaries.
  • 46. Community ! n. A feeling of fellowship with others sharing similar goals.
  • 47. “The Rust community seems to be populated entirely by human beings. I have no idea how this was done.” — Jamie Brandon
  • 48. It takes a village… Community focus from the start: Rust 1.0 had > 1,000 contributors Welcoming, pragmatic culture ! Developed “in the open” Much iteration; humility is key! ! Clear leadership Mix of academic and engineering backgrounds “Keepers of the vision”
  • 50. Memory safety Concurrency Abstraction Stability without garbage collection data races overhead stagnation Hack without fear! Articulating the vision
  • 51. Watch the video with slide synchronization on InfoQ.com! http://www.infoq.com/presentations/rust- thread-safety