0% found this document useful (0 votes)
3 views

COMP3007_Modern_Programming_Languages (5)

The document covers Rust's concurrency model, including concepts such as threads, message passing, shared state, and async/await. It highlights the importance of Rust's ownership and type system in preventing common concurrency issues like race conditions and deadlocks. The presentation concludes by emphasizing the need to understand these concepts for writing efficient and safe concurrent programs.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

COMP3007_Modern_Programming_Languages (5)

The document covers Rust's concurrency model, including concepts such as threads, message passing, shared state, and async/await. It highlights the importance of Rust's ownership and type system in preventing common concurrency issues like race conditions and deadlocks. The presentation concludes by emphasizing the need to understand these concepts for writing efficient and safe concurrent programs.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 22

COMP3007 - Modern Programming Languages

Week 7: Rust - Concurrency

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel

Department of Computer Engineering

Fall 2024-2025

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 1 / 22
Outline

1 Introduction to Concurrency

2 Common Concurrency Problems

3 Using Threads

4 Using move Closures with Threads

5 Message Passing Between Threads

6 Shared State Concurrency

7 Async/Await

8 Conclusion

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 2 / 22
What is Concurrent Programming?

Running multiple parts of a program simultaneously


Different from parallel programming:
Concurrent: Managing multiple tasks at once
Parallel: Executing multiple tasks at once
Important for:
Improved performance
Better resource utilization
Responsive applications

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 3 / 22
Thread Model in Rust

Rust uses 1:1 threading model


One OS thread per language thread
Direct mapping to system threads
More resource-intensive but better performance
Alternative models:
Green threads (M:N model)
Async/await for lightweight concurrency
OS threads provide full parallelism on multicore systems

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 4 / 22
Race Conditions
Occurs when multiple threads access shared data
Result depends on timing of thread execution
Example: Multiple threads incrementing a counter
1 // This code has a race condition !
2 static mut COUNTER : u32 = 0;
3
4 fn main () {
5 let mut handles = vec ![];
6
7 for _ in 0..10 {
8 handles .push( thread :: spawn (|| {
9 unsafe {
10 COUNTER += 1; // Race condition here!
11 }
12 }));
13 }
14 }

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 5 / 22
Deadlocks

Occurs when threads wait for each other indefinitely


Classic example: Two threads, two resources
Each thread holds one resource, waits for the other
1 use std:: sync ::{ Mutex , Arc};
2 use std:: thread;
3 fn main () {
4 let resource_a = Arc::new(Mutex ::new (()));
5 let resource_b = Arc::new(Mutex ::new (()));
6
7 let a1 = Arc:: clone (& resource_a);
8 let b1 = Arc:: clone (& resource_b);
9 let thread1 = thread :: spawn(move || {
10 let _a = a1.lock ().unwrap (); // Lock A
11 thread :: sleep(Duration :: from_millis (100));
12 let _b = b1.lock ().unwrap (); // Wait for B
13 });
14
15 let a2 = Arc:: clone (& resource_a);
16 let b2 = Arc:: clone (& resource_b);
17 let thread2 = thread :: spawn(move || {
18 let _b = b2.lock ().unwrap (); // Lock B
19 let _a = a2.lock ().unwrap (); // Wait for A
20 });
21 }

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 6 / 22
Memory Safety in Concurrent Code

Common issues in concurrent programming:


Invalid memory access
Use after free
Double free
Buffer overflows
Rust’s safety guarantees:
Ownership system prevents data races
Type system ensures thread safety
Compile-time checks for concurrent access

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 7 / 22
Rust’s Concurrency Guarantees

Ownership and borrowing rules prevent:


Data races at compile time
Invalid concurrent memory access
Use of data after moving between threads
Thread safety through type system:
Send: Type can be transferred between threads
Sync: Type can be shared between threads
Most primitive types are both Send and Sync

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 8 / 22
Safe Concurrent Counter Example

1 use std:: sync ::{Arc , Mutex };


2 use std:: thread;
3
4 fn main () {
5 // Thread -safe counter using Arc and Mutex
6 let counter = Arc::new(Mutex ::new (0));
7 let mut handles = vec ![];
8
9 for _ in 0..10 {
10 let counter = Arc:: clone (& counter);
11 let handle = thread :: spawn(move || {
12 let mut num = counter.lock ().unwrap ();
13 *num += 1;
14 });
15 handles.push(handle);
16 }
17
18 // Wait for all threads
19 for handle in handles {
20 handle.join ().unwrap ();
21 }
22
23 println !("Final count: {}",
24 *counter.lock ().unwrap ());
25 }

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 9 / 22
Creating a New Thread
1 use std :: thread ;
2 use std :: time :: Duration ;
3
4 fn main () {
5 thread :: spawn (|| {
6 for i in 1..10 {
7 println !("hi number {} from the spawned
thread !", i);
8 thread :: sleep( Duration :: from_millis (1));
9 }
10 });
11

12 for i in 1..5 {
13 println !("hi number {} from the main thread !",
i);
14 thread :: sleep( Duration :: from_millis (1));
15 }
16 }
Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department
COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 10 / 22
Waiting for All Threads to Finish

1 use std:: thread;


2 use std:: time :: Duration;
3
4 fn main () {
5 let handle = thread :: spawn (|| {
6 for i in 1..10 {
7 println !("hi number {} from the spawned thread!", i);
8 thread :: sleep(Duration :: from_millis (1));
9 }
10 });
11
12 for i in 1..5 {
13 println !("hi number {} from the main thread!", i);
14 thread :: sleep(Duration :: from_millis (1));
15 }
16
17 handle.join ().unwrap ();
18 }

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 11 / 22
Using move Closures with Threads

1 use std :: thread ;


2

3 fn main () {
4 let v = vec ![1, 2, 3];
5
6 let handle = thread :: spawn(move || {
7 println !("Here 's a vector : {:?}", v);
8 });
9
10 handle .join (). unwrap ();
11 }

The move keyword forces the closure to take ownership of the values
it uses

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 12 / 22
Message Passing

Rust implements message-passing concurrency using channels


A channel has two halves: a transmitter and a receiver
Implements the ”Do not communicate by sharing memory; instead,
share memory by communicating” principle

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 13 / 22
Creating a Channel

1 use std :: sync :: mpsc;


2 use std :: thread ;
3
4 fn main () {
5 let (tx , rx) = mpsc :: channel ();
6
7 thread :: spawn(move || {
8 let val = String :: from("hi");
9 tx.send(val). unwrap ();
10 });
11
12 let received = rx.recv (). unwrap ();
13 println !("Got: {}", received );
14 }

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 14 / 22
Shared State Concurrency

Shared memory concurrency is also possible in Rust


Rust’s type system and ownership rules prevent data races
Key concepts: Mutex and Arc

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 15 / 22
Using Mutexes

1 use std :: sync :: Mutex;


2
3 fn main () {
4 let m = Mutex :: new (5);
5
6 {
7 let mut num = m.lock (). unwrap ();
8 *num = 6;
9 }
10
11 println !("m = {:?}", m);
12 }

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 16 / 22
Sharing a Mutex Between Multiple Threads

1 use std:: sync ::{ Mutex , Arc};


2 use std:: thread;
3
4 fn main () {
5 let counter = Arc::new(Mutex ::new (0));
6 let mut handles = vec ![];
7
8 for _ in 0..10 {
9 let counter = Arc:: clone (& counter);
10 let handle = thread :: spawn(move || {
11 let mut num = counter.lock ().unwrap ();
12 *num += 1;
13 });
14 handles.push(handle);
15 }
16
17 for handle in handles {
18 handle.join ().unwrap ();
19 }
20
21 println !("Result: {}", *counter.lock ().unwrap ());
22 }

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 17 / 22
Introduction to Async/Await

Async/await is Rust’s built-in tool for writing asynchronous


programming
Allows you to write asynchronous code that looks like synchronous
code
Based on Futures, but much easier to use

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 18 / 22
Basic Async/Await Example

1 use futures :: executor :: block_on ;


2
3 async fn hello_world () {
4 println !("hello , world !");
5 }
6
7 fn main () {
8 let future = hello_world (); // Nothing is printed
9 block_on ( future ); // `hello , world !` is printed
10 }

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 19 / 22
Async/Await with Multiple Futures
1 use futures :: executor :: block_on;
2
3 async fn learn_song () -> String {
4 String :: from("song")
5 }
6
7 async fn sing_song(song: String) {
8 println !("Singing: {}", song);
9 }
10
11 async fn dance () {
12 println !("Dancing");
13 }
14
15 async fn learn_and_sing () {
16 let song = learn_song ().await;
17 sing_song(song).await;
18 }
19
20 async fn async_main () {
21 let f1 = learn_and_sing ();
22 let f2 = dance ();
23
24 futures :: join !(f1 , f2);
25 }
26
27 fn main () {
28 block_on(async_main ());
29 }

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 20 / 22
Conclusion

Rust provides powerful tools for concurrent programming


Ownership and type system prevent common concurrency bugs
Multiple paradigms supported: threads, message passing, shared state
Async/await provides an ergonomic way to write asynchronous code
Understanding these concepts is crucial for writing efficient, safe
concurrent programs

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 21 / 22
Thank You! Any Questions?

Dr. Öğr. Üyesi Yusuf Kürşat Tuncel (Department


COMP3007
of Computer
- Modern
Engineering)
Programming Languages Fall 2024-2025 22 / 22

You might also like