6 April 2023
Introduction: Concurrency is the ability of a program to perform multiple tasks simultaneously. Rust is designed to be a safe and fast language, and its support for concurrency is one of its key features. In this guide, we will explore how to write concurrent code in Rust, using Rust's ownership and borrowing system, threads, and message passing. We'll provide code examples throughout the guide to illustrate the concepts.
Threads in Rust: In Rust, you can create threads using the std::thread::spawn
function. For example, consider the following code:
use std::thread; fn main() { let handle = thread::spawn(|| { // thread code here }); // do other things here handle.join().unwrap(); }
In this code, we create a new thread using thread::spawn
, which takes a closure as an argument. The closure contains the code that will be run in the new thread. We store the thread handle in the handle
variable and then do other things in the main thread. Finally, we call handle.join()
to wait for the thread to finish executing.
Sharing Data Between Threads: One of the challenges of writing concurrent code is sharing data between threads. Rust's ownership and borrowing system ensures that only one thread can own a piece of data at a time. To share data between threads, we use Rust's Arc
(Atomic Reference Counting) and Mutex
(Mutual Exclusion) types.
use std::sync::{Arc, Mutex}; use std::thread; fn main() { let data = Arc::new(Mutex::new(0)); let mut threads = Vec::new(); for i in 0..10 { let data = Arc::clone(&data); let handle = thread::spawn(move || { let mut data = data.lock().unwrap(); *data += i; }); threads.push(handle); } for handle in threads { handle.join().unwrap(); } println!("{:?}", data); }
In this code, we create an Arc<Mutex<T>>
value called data
, where T
is the type of data we want to share between threads. We then create 10 threads, each of which increments the value of data
by its thread number. The Arc::clone
function creates a new reference to data
that can be moved into the thread closure. Inside the closure, we lock the mutex using the lock
method, modify the value, and then unlock the mutex. Finally, we wait for all the threads to finish executing and then print the value of data
.
Message Passing: Another way to share data between threads is through message passing. Rust provides channels for message passing, which can be used to send and receive data between threads.
use std::sync::mpsc; use std::thread; fn main() { let (tx, rx) = mpsc::channel(); let handle = thread::spawn(move || { let data = 42; tx.send(data).unwrap(); }); let received = rx.recv().unwrap(); println!("{}", received); handle.join().unwrap(); }
In this code, we create a channel using mpsc::channel
. We then spawn a new thread that sends the value 42
through the channel using the send
method. In the main thread, we receive the value using the recv
method and print it. Finally, we wait for the thread to finish executing using handle.join()
.
Conclusion: In this guide, we explored how to write concurrent code in Rust using threads and message passing. Rust's ownership and borrowing system, combined with its support for concurrency, makes it a powerful language for building high-performance and scalable applications. We hope this guide has provided you with a solid understanding of concurrency in Rust and has given you the tools you need to start writing your own concurrent programs. If you have any questions or comments, please leave them in the comments section below.
Official documentation:
CONTACT
+44 (0)20 8446 7555
Copyright © 2024 JBI Training. All Rights Reserved.
JB International Training Ltd - Company Registration Number: 08458005
Registered Address: Wohl Enterprise Hub, 2B Redbourne Avenue, London, N3 2BS
Modern Slavery Statement & Corporate Policies | Terms & Conditions | Contact Us