Звичайні потоки
Потоки 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 вбиває дочірні потоки, коли повертається, але інша функція просто повернеться і залишить їх працювати.
- Це буде використання стеку після повернення, що порушує безпеку пам'яті!
- Як цього уникнути? Дивіться наступний слайд.