Ce face Arc
Arc<T> (atomically reference counted) face același lucru ca Rc: mai mulți proprietari pentru aceeași valoare, eliberată când dispare ultimul. Diferența este că actualizează contorul cu operații atomice, deci poate fi trimis în alte fire.
Modelul obișnuit: creezi Arc::new(date), faci un Arc::clone(&date) pentru fiecare fir și îl muți în fir cu move. Datele pot fi doar citite. Pentru modificare din mai multe fire, folosește Arc<Mutex<T>>, Arc<RwLock<T>> sau tipuri atomice.
Operațiile atomice sunt puțin mai lente, așa că într-un singur fir rămâi la Rc.
Parametri
| Parametru | Descriere |
|---|---|
data |
Valoarea împărțită (la new). |
Ce returnează
new și clone returnează Arc<T>; strong_count returnează numărul de proprietari.
Exemple
Exemplul 1: Date comune pentru mai multe fire
Fiecare fir primește propriul Arc spre aceeași listă de prețuri. Rezultatele vin prin join, în ordinea firelor.
use std::sync::Arc;
use std::thread;
fn main() {
let preturi = Arc::new(vec![12.5, 30.0, 7.25, 50.0]);
let mut fire = Vec::new();
for (i, cota_tva) in [0.09, 0.19].into_iter().enumerate() {
let preturi = Arc::clone(&preturi);
fire.push(thread::spawn(move || {
let total: f64 = preturi.iter().map(|p| p * (1.0 + cota_tva)).sum();
format!("firul {i}: total cu TVA {:.0}% = {total:.2} lei", cota_tva * 100.0)
}));
}
for f in fire {
println!("{}", f.join().unwrap());
}
println!("proprietari la final: {}", Arc::strong_count(&preturi));
}
Rezultat
firul 0: total cu TVA 9% = 108.73 lei
firul 1: total cu TVA 19% = 118.70 lei
proprietari la final: 1
Exemplul 2: strong_count în timp ce firele lucrează
Cu thread::scope știm sigur când se termină firele. În interior, fiecare fir ține un Arc.
use std::sync::Arc;
use std::thread;
fn main() {
let mesaj = Arc::new(String::from("Salut din Iași"));
println!("înainte: {}", Arc::strong_count(&mesaj));
let copie1 = Arc::clone(&mesaj);
let copie2 = Arc::clone(&mesaj);
println!("cu două copii: {}", Arc::strong_count(&mesaj));
thread::scope(|s| {
s.spawn(move || copie1.len());
s.spawn(move || copie2.len());
});
println!("după fire: {}", Arc::strong_count(&mesaj));
}
Rezultat
înainte: 1
cu două copii: 3
după fire: 1
Greșeli frecvente
- Scrii
movefără să clonezi înainteArc-ul: primul fir mutăArc-ul original și al doilea nu mai are ce folosi (use of moved value). - Încerci să modifici datele dintr-un
Arc<Vec<T>>: nu se poate. Pune unMutexînăuntru.
Comenzi înrudite
Rc: Pointer cu numărarea referințelor: mai mulți proprietari împart aceeași valoare, eliberată când dispare ultimul.Mutex: Protejează o valoare folosită din mai multe fire: lock() așteaptă până când firul curent este singurul cu acces.thread::spawn: Pornește un fir de execuție nou care rulează funcția dată; join() așteaptă terminarea lui și îi dă rezultatul.AtomicUsize: Număr întreg care poate fi citit și modificat din mai multe fire fără Mutex, cu operații atomice.