The ‘Send‘ and ‘Sync‘ traits in Rust are used to indicate safe concurrency in multi-threaded programming.
‘Send‘ trait indicates that data can be safely transferred across threads, while ‘Sync‘ trait indicates that data can be safely shared between threads without causing data races.
Here are the differences between ‘Send‘ and ‘Sync‘ traits:
#### Send
The ‘Send‘ trait indicates that a type is safe to be transferred across threads. When a type implements the ‘Send‘ trait, it is guaranteed to be free of data races when passed between threads. For example, a ‘String‘ can be safely transferred between threads because it is immutable and doesn’t have any interior mutability. A mutex guard, on the other hand, cannot be transferred between threads because it represents a mutable state and could cause data races.
Here’s an example of using the ‘Send‘ trait:
use std::thread;
fn main() {
let s = String::from("hello");
let handle = thread::spawn(|| {
println!("s: {}", s);
});
handle.join().unwrap();
}
In this example, ‘String‘ implements ‘Send‘, so it can be safely passed to the closure spawned by the ‘thread::spawn‘ function.
#### Sync
The ‘Sync‘ trait indicates that a type is safe to be shared between threads. When a type implements the ‘Sync‘ trait, it is guaranteed to be free of data races when accessed from multiple threads simultaneously. For example, a ‘u32‘ can be safely shared between threads because it is immutable and has no interior mutability. A reference-counted type like ‘Arc<T>‘ can also be safely shared between threads because it ensures that the reference count is updated atomically.
Here’s an example of using the ‘Sync‘ trait:
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}
In this example, ‘Mutex<T>‘ implements ‘Sync‘, so it can be safely shared between threads. The ‘Arc<T>‘ type also implements ‘Sync‘, but it requires the ‘Mutex<T>‘ to synchronize access to the interior value.
So, when should you use each of these traits?
Use ‘Send‘ when you want to transfer ownership of data between threads, and use ‘Sync‘ when you want to share data between threads. In general, if a type is immutable and doesn’t have any interior mutability, it can implement both ‘Send‘ and ‘Sync‘. If a type is mutable, it can only implement ‘Sync‘, and requires synchronization to be accessed from multiple threads.