Звичайні потоки

Потоки Rust працюють так само, як і в інших мовах:

use std::thread;
use std::time::Duration;

fn main() {
    thread::spawn(|| {
        for i in 0..10 {
            println!("Підрахунок в потоці: {i}!");
            thread::sleep(Duration::from_millis(5));
        }
    });

    for i in 0..5 {
        println!("Головний потік: {i}");
        thread::sleep(Duration::from_millis(5));
    }
}
  • Породження нових потоків не призводить до автоматичної затримки завершення програми в кінці main.
  • Паніка потоків не залежить одна від одної.
    • Паніки можуть нести корисне навантаження, яке можна розпакувати за допомогою downcast_ref.
This slide should take about 15 minutes.
  • API потоків Rust зовні не надто відрізняються від API, наприклад, C++.

  • Запустіть приклад.

    • Таймінг 5 мс є достатньо вільним, щоб головний і породжений потоки залишалися переважно в одному ритмі.
    • Зверніть увагу, що програма завершується до того, як породжений потік досягне 10!
    • Це тому, що main завершує програму, а породжені потоки не змушують її продовжувати.
      • За бажанням можна порівняти з pthreads/C++ std::thread/boost::thread.
  • Як нам дочекатися завершення породженого потоку?

  • thread::spawn повертає JoinHandle. Перегляньте документацію.

    • У JoinHandle є метод .join(), який блокує.
  • Використовуйте let handle = thread::spawn(...), а потім handle.join(), щоб дочекатися завершення потоку і змусити програму дорахувати до 10..

  • А що, якщо ми хочемо повернути значення?

  • Перегляньте документацію ще раз:

    • Закриття thread::spawn повертає T.
    • JoinHandle .join() повертає thread::Result<T>
  • Використовуйте значення Result, що повертається з handle.join(), щоб отримати доступ до значення, що повертається.

  • Гаразд, а як щодо іншого випадку?

    • Викликає паніку в потоці. Зауважте, що це не впливає на main.
    • Дає доступ до корисного навантаження паніки. Це гарний час, щоб поговорити про Any.
  • Тепер ми можемо повертати значення з потоків! А як щодо отримання вхідних даних?

    • Захоплюємо щось за посиланням у закритті потоку.
    • Повідомлення про помилку вказує на те, що ми повинні його перемістити.
    • Переміщуємо його, бачимо, що можемо обчислити, а потім повертаємо похідне значення.
  • Якщо ми хочемо позичити?

    • Main вбиває дочірні потоки, коли повертається, але інша функція просто повернеться і залишить їх працювати.
    • Це буде використання стеку після повернення, що порушує безпеку пам'яті!
    • Як цього уникнути? Дивіться наступний слайд.