0Pricing
Learn Rust Coding · Lekcja

Współdzielenie za pomocą Arc i Mutex

Bezpiecznie zmodyfikuje Pan/Pani współdzielony stan.

Współdzielenie za pomocą Arc i Mutex to bezpłatna lekcja Learn Rust Coding na CoddyKit. To lekcja 3 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Learn Rust Coding, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Learn Rust Coding zawiera 4 lekcji w sumie.

Potrzeba współdzielonego stanu

Czasami kilka wątków musi odczytywać lub aktualizować te same dane. Przeniesienie własności do jednego wątku nie wystarczy.

Rust zapewnia bezpieczne współdzielenie własności między wątkami za pomocą Arc oraz bezpieczną modyfikację za pomocą Mutex. Razem umożliwiają współdzielony, modyfikowalny stan.

Arc: atomowe zliczanie odwołań

Arc oznacza atomically reference counted, czyli atomowe zliczanie odwołań. Działa podobnie jak Rc, ale jego licznik korzysta z operacji atomowych, dzięki czemu jest bezpieczny w wielu wątkach.

Klonowanie Arc nie kopiuje danych. Zwiększa tylko licznik i zwraca kolejny uchwyt do tej samej wartości.

use std::sync::Arc;

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

Współdzielenie Arc między wątkami

Aby współdzielić dane tylko do odczytu, sklonuj Arc raz dla każdego wątku i przenieś każdą kopię do odpowiedniego wątku. Wszystkie wątki wskazują tę samą alokację.

Ponieważ Arc implementuje Send i Sync, ten kod kompiluje się bez problemów.

use std::sync::Arc;
use std::thread;

fn main() {
    let data = Arc::new(vec![10, 20, 30]);
    let mut handles = vec![];
    for i in 0..3 {
        let d = Arc::clone(&data);
        handles.push(thread::spawn(move || println!("{}", d[i])));
    }
    for h in handles { h.join().unwrap(); }
}

Sam Arc zapewnia tylko odczyt

Arc zapewnia współdzieloną własność, ale tylko współdzielony, niezmienny dostęp do przechowywanej wartości.

Nie można bezpośrednio modyfikować danych przez Arc, ponieważ jednoczesny dostęp wielu wątków prowadziłby do wyścigu. Potrzebna jest mutowalność wewnętrzna z blokadą.

Mutex: wzajemne wykluczanie

Mutex chroni dane, tak aby w danej chwili tylko jeden wątek mógł uzyskać do nich dostęp. Dostęp uzyskuje się, wywołując lock.

lock zwraca Result; rozpakowanie wyniku daje strażnika w postaci inteligentnego wskaźnika. Pozostałe wątki są blokowane do momentu zniszczenia strażnika.

use std::sync::Mutex;

fn main() {
    let m = Mutex::new(0);
    {
        let mut guard = m.lock().unwrap();
        *guard += 5;
    }
    println!("{:?}", m);
}

Strażnik i RAII

Wartość zwracana przez lock to MutexGuard. Do przechowywanych danych uzyskuje się dostęp przez dereferencję za pomocą *.

Gdy strażnik wyjdzie poza zakres, blokada zostanie automatycznie zwolniona. Ten styl RAII zapobiega zapomnieniu o odblokowaniu.

Łączenie Arc i Mutex

Aby współdzielić modyfikowalny stan między wątkami, umieść Mutex wewnątrz Arc. Arc współdzieli własność, a Mutex chroni modyfikacje.

Ten wzorzec, Arc<Mutex<T>>, jest standardowym sposobem implementowania współdzielonego, modyfikowalnego stanu w języku Rust.

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

fn main() {
    let counter = Arc::new(Mutex::new(0));
    let c = Arc::clone(&counter);
    *c.lock().unwrap() += 1;
    println!("{}", *counter.lock().unwrap());
}

Współdzielony licznik

W tym przykładzie dziesięć wątków zwiększa współdzielony licznik. Każdy z nich klonuje Arc, blokuje Mutex i dodaje jeden.

Ponieważ blokada szeregowo porządkuje dostęp, końcowa suma zawsze wynosi dokładnie dziesięć.

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 || {
            *c.lock().unwrap() += 1;
        }));
    }
    for h in handles { h.join().unwrap(); }
    println!("{}", *counter.lock().unwrap());
}

Krótkie sekcje krytyczne

Kod wykonywany podczas utrzymywania blokady to sekcja krytyczna. Pozostałe wątki czekają w tym miejscu, dlatego sekcja powinna być krótka.

Zablokuj dane, wykonaj minimalną aktualizację, a następnie zwolnij blokadę. Unikaj intensywnych obliczeń i operacji wejścia-wyjścia podczas utrzymywania blokady.

use std::sync::Mutex;

fn main() {
    let m = Mutex::new(Vec::new());
    {
        let mut v = m.lock().unwrap();
        v.push(1);
    } // lock released here
    println!("{:?}", m.lock().unwrap());
}

Zakleszczenia i zatrucie blokady

Jeśli wątek dwukrotnie zablokuje ten sam Mutex albo dwa wątki zablokują dwa muteksy w odwrotnej kolejności, może dojść do zakleszczenia i wiecznego zawieszenia programu.

Jeśli wątek zgłosi panic podczas utrzymywania blokady, Mutex zostanie oznaczony jako zatruty, a późniejsze wywołania lock zwrócą Err.

RwLock dla wielu czytelników

Gdy odczyty zdecydowanie przeważają nad zapisami, RwLock może być lepszy niż Mutex. Umożliwia jednoczesny dostęp wielu czytelników albo wyłączny dostęp jednego piszącego.

Do współdzielonego dostępu używaj read, a do wyłącznego dostępu — write.

use std::sync::RwLock;

fn main() {
    let lock = RwLock::new(5);
    {
        let r = lock.read().unwrap();
        println!("read {}", *r);
    }
    *lock.write().unwrap() += 1;
    println!("{}", *lock.read().unwrap());
}

Szybki test

Sprawdź swoją wiedzę o Arc i Mutex.

Podsumowanie

Dowiedziałeś się, że Arc współdzieli własność między wątkami za pomocą atomowego zliczania odwołań, ale umożliwia tylko niezmienny dostęp.

Mutex chroni modyfikacje, udostępniając strażnika, który zwalnia blokadę podczas niszczenia. Połącz je jako Arc<Mutex<T>>, aby uzyskać współdzielony, modyfikowalny stan, pamiętając o zakleszczeniach i zatruciu blokad.

Teraz połączysz wątki i zbierzesz wyniki ich pracy.

Często zadawane pytania

Czy lekcja „Współdzielenie za pomocą Arc i Mutex” jest bezpłatna?

Tak — pełny tekst „Współdzielenie za pomocą Arc i Mutex” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Learn Rust Coding, przejdź na CoddyKit PRO. Kurs Learn Rust Coding zawiera 4 lekcji w sumie.

Co nauczysz się w „Współdzielenie za pomocą Arc i Mutex”?

Bezpiecznie zmodyfikuje Pan/Pani współdzielony stan. Ćwiczysz Learn Rust Coding z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Learn Rust Coding?

Nie wymagamy żadnego doświadczenia. Learn Rust Coding w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 3 z 4.

Ile czasu zajmuje lekcja „Współdzielenie za pomocą Arc i Mutex”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Learn Rust Coding?

Tak. Każda lekcja Learn Rust Coding zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Uruchamianie wątków
  2. Przenoszenie danych do wątków
  3. Współdzielenie za pomocą Arc i Mutex
  4. Dołączanie wątków i zbieranie wyników
← Powrót do Learn Rust Coding