Lær Rust-programmering · leksjon

Dele tilstand med Arc/Mutex

Trygge delte data

Leksjon 2 av 413 trinn

Dele tilstand med Arc/Mutex er en gratis leksjon i Lær Rust-programmering på CoddyKit. Dette er leksjon 2 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Lær Rust-programmering, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Lær Rust-programmering inneholder totalt 4 leksjoner.

Hvorfor delt tilstand er vanskelig

Noen ganger er meldingsutveksling ikke nok, og flere tråder må faktisk lese og skrive til de samme dataene. Rust lar Dem ikke dele en muterbar verdi mellom tråder uten beskyttelse, fordi det kan føre til en datakappløpssituasjon.

De to verktøyene De kombinerer, er:

  • Arc for delt eierskap på tvers av tråder.
  • Mutex for trygg, eksklusiv mutering.

Rc er ikke trådsikker

Rc gir delt eierskap, men bare i én tråd. Referansetelleren synkroniseres ikke, så kompilatoren nekter å sende den mellom tråder. For deling i flere tråder trenger De Arc (Atomically Reference Counted).

Arc fungerer som Rc, men oppdaterer telleren med atomiske operasjoner, slik at klonene er trygge på tvers av tråder.

use std::sync::Arc;

fn main() {
    let data = Arc::new(vec![1, 2, 3]);
    let clone1 = Arc::clone(&data);
    println!("original: {:?}", data);
    println!("clone:    {:?}", clone1);
    println!("count:    {}", Arc::strong_count(&data));
}

Mutex gir eksklusiv tilgang

En Mutex pakker inn data og garanterer at bare én tråd får tilgang til dem om gangen. De kaller .lock() for å få en MutexGuard, som derefererer til den indre verdien. Låsen frigjøres automatisk når vakten går ut av scopet.

use std::sync::Mutex;

fn main() {
    let m = Mutex::new(5);
    {
        let mut num = m.lock().unwrap();
        *num += 10;
    } // guard dropped here, lock released
    println!("value = {:?}", m.lock().unwrap());
}

Kombinere Arc og Mutex

For å dele muterbare data mellom tråder pakker De dem inn som Arc>:

  • Arc lar mange tråder eie et håndtak til de samme dataene.
  • Mutex lar hver tråd mutere dataene trygt, én om gangen.

Klone Arc for hver tråd før De starter dem.

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

fn main() {
    let counter = Arc::new(Mutex::new(0));
    let c = Arc::clone(&counter);
    let handle = thread::spawn(move || {
        let mut n = c.lock().unwrap();
        *n += 1;
    });
    handle.join().unwrap();
    println!("counter = {}", *counter.lock().unwrap());
}

En delt teller på tvers av mange tråder

Det klassiske eksempelet: ti tråder øker hver sin delte teller. Hver tråd har sin egen Arc-klone og låser Mutex for å legge til én. Når alle trådene er joinet, er totalen nøyaktig 10, uten noen datakappløpssituasjon.

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 c = Arc::clone(&counter);
        handles.push(thread::spawn(move || {
            let mut num = c.lock().unwrap();
            *num += 1;
        }));
    }
    for h in handles {
        h.join().unwrap();
    }
    println!("Result: {}", *counter.lock().unwrap());
}

Låsens omfang er viktig

MutexGuard holder låsen til den slippes. Hvis den holdes under langsomt arbeid, blokkeres andre tråder. Hold kritiske seksjoner korte: lås, muter, frigjør. Hvis låsen pakkes inn i en liten blokk, sikrer det at den slippes før eventuell videre behandling.

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

fn main() {
    let log = Arc::new(Mutex::new(Vec::new()));
    let mut handles = vec![];
    for i in 0..3 {
        let l = Arc::clone(&log);
        handles.push(thread::spawn(move || {
            {
                let mut v = l.lock().unwrap();
                v.push(i);
            } // released quickly
        }));
    }
    for h in handles { h.join().unwrap(); }
    let mut result = log.lock().unwrap().clone();
    result.sort();
    println!("{:?}", result);
}

Vrangelåser: En reell risiko

En vrangelås oppstår når to tråder hver holder en lås som den andre trenger, og begge venter for alltid. Rust forhindrer datakappløpssituasjoner, men ikke vrangelåser. Unngå dem ved alltid å låse flere mutexer i samme rekkefølge og holde låsene korte.

Unngå også å låse den samme Mutex to ganger i én tråd; standardutgaven av Mutex kan ikke låses rekursivt.

Forgiftning når en tråd får panikk

Hvis en tråd får panikk mens den holder en lås, blir Mutex forgiftet. Senere kall til .lock() returnerer Err, slik at De vet at dataene kan være inkonsistente. De kan hente ut den indre vakten med into_inner() på feilen hvis De avgjør at dataene fortsatt kan brukes.

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

fn main() {
    let data = Arc::new(Mutex::new(0));
    let d = Arc::clone(&data);
    let _ = thread::spawn(move || {
        let mut g = d.lock().unwrap();
        *g = 7;
        panic!("boom"); // poisons the mutex
    }).join();
    match data.lock() {
        Ok(g) => println!("ok: {}", *g),
        Err(poisoned) => println!("recovered: {}", *poisoned.into_inner()),
    }
}

RwLock for mange lesere

Når lesinger er langt vanligere enn skrivinger, kan en RwLock være raskere enn en Mutex. Den tillater mange samtidige lesere eller én skriver. Bruk .read() for delt tilgang og .write() for eksklusiv tilgang.

use std::sync::{Arc, RwLock};
use std::thread;

fn main() {
    let config = Arc::new(RwLock::new(String::from("v1")));
    let reader = Arc::clone(&config);
    let r = thread::spawn(move || {
        let val = reader.read().unwrap();
        println!("read: {}", *val);
    });
    r.join().unwrap();
    {
        let mut w = config.write().unwrap();
        *w = String::from("v2");
    }
    println!("final: {}", *config.read().unwrap());
}

Atomiske operasjoner for enkle tellere

For én heltallsteller er en full Mutex unødvendig omfattende. Typer som AtomicUsize tilbyr låsfrie oppdateringer via metoder som fetch_add. Pakk dem inn i Arc for å dele dem mellom tråder. Velg en Ordering; SeqCst er det enkleste trygge standardvalget.

use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;

fn main() {
    let counter = Arc::new(AtomicUsize::new(0));
    let mut handles = vec![];
    for _ in 0..5 {
        let c = Arc::clone(&counter);
        handles.push(thread::spawn(move || {
            c.fetch_add(1, Ordering::SeqCst);
        }));
    }
    for h in handles { h.join().unwrap(); }
    println!("count = {}", counter.load(Ordering::SeqCst));
}

Velge riktig verktøy

En rask veiledning for delt tilstand:

  • Channel: overfør eierskap i en rørledningsstil.
  • Arc<Mutex>: delt muterbar struktur med blandet lesing og skriving.
  • Arc<RwLock>: delte data som hovedsakelig leses.
  • Atomics: tellere eller flagg av én enkel type.

Foretrekk det enkleste verktøyet som passer, og bruk låser bare når meldingsutveksling ikke beskriver problemet på en god måte.

Kort sjekk

Test forståelsen Deres av delt tilstand.

Oppsummering

De har lært hvordan tilstand kan deles trygt mellom tråder:

  • Arc muliggjør trådsikkert delt eierskap; det gjør ikke Rc.
  • Mutex gir eksklusiv mutering via en vakt som låser opp automatisk.
  • Arc<Mutex<T>> er standardmønsteret for delte muterbare data.
  • Hold låsenes omfang kort, og vær oppmerksom på vrangelåser og forgiftning.
  • RwLock passer for data som hovedsakelig leses; atomiske operasjoner passer for enkle tellere.
Gratis å komme i gang

Lær deg Rust med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
39
Leksjoner
144

Ofte stilte spørsmål

Er leksjonen «Dele tilstand med Arc/Mutex» gratis?

Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Lær Rust-programmering, inkludert «Dele tilstand med Arc/Mutex», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Lær Rust-programmering inneholder totalt 4 leksjoner.

Hva lærer jeg i «Dele tilstand med Arc/Mutex»?

Trygge delte data Du øver på Lær Rust-programmering med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med Lær Rust-programmering?

Ingen tidligere erfaring er nødvendig. Lær Rust-programmering på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 2 av 4.

Hvor lang tid tar leksjonen «Dele tilstand med Arc/Mutex»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne Lær Rust-programmering-leksjonen?

Ja. Alle Lær Rust-programmering-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. mpsc-kanaler
  2. Dele tilstand med Arc/Mutex
  3. Avgrensede tråder
  4. Crossbeam-kanaler
← Tilbake til Lær Rust-programmering