You've already forked comprehensive-rust
mirror of
https://github.com/google/comprehensive-rust.git
synced 2025-12-22 06:47:49 +02:00
Update Concurrency course with times (#2007)
As I mentioned in #1536: * Break into segments at approximately the places @fw-immunant put breaks * Move all of the files into `src/concurrency` * Add timings and segment/session metadata so course outlines appear There's room for more work here, including some additional feedback from @fw-immunant after the session I observed, but let's do one step at a time :)
This commit is contained in:
committed by
GitHub
parent
a03b7e68e5
commit
face5af783
@@ -1,74 +1,3 @@
|
||||
# Threads
|
||||
|
||||
Rust threads work similarly to threads in other languages:
|
||||
|
||||
```rust,editable
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
fn main() {
|
||||
thread::spawn(|| {
|
||||
for i in 1..10 {
|
||||
println!("Count in thread: {i}!");
|
||||
thread::sleep(Duration::from_millis(5));
|
||||
}
|
||||
});
|
||||
|
||||
for i in 1..5 {
|
||||
println!("Main thread: {i}");
|
||||
thread::sleep(Duration::from_millis(5));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Threads are all daemon threads, the main thread does not wait for them.
|
||||
- Thread panics are independent of each other.
|
||||
- Panics can carry a payload, which can be unpacked with `downcast_ref`.
|
||||
|
||||
<details>
|
||||
|
||||
- Rust thread APIs look not too different from e.g. C++ ones.
|
||||
|
||||
- Run the example.
|
||||
- 5ms timing is loose enough that main and spawned threads stay mostly in
|
||||
lockstep.
|
||||
- Notice that the program ends before the spawned thread reaches 10!
|
||||
- This is because main ends the program and spawned threads do not make it
|
||||
persist.
|
||||
- Compare to pthreads/C++ std::thread/boost::thread if desired.
|
||||
|
||||
- How do we wait around for the spawned thread to complete?
|
||||
- [`thread::spawn`] returns a `JoinHandle`. Look at the docs.
|
||||
- `JoinHandle` has a [`.join()`] method that blocks.
|
||||
|
||||
- Use `let handle = thread::spawn(...)` and later `handle.join()` to wait for
|
||||
the thread to finish and have the program count all the way to 10.
|
||||
|
||||
- Now what if we want to return a value?
|
||||
- Look at docs again:
|
||||
- [`thread::spawn`]'s closure returns `T`
|
||||
- `JoinHandle` [`.join()`] returns `thread::Result<T>`
|
||||
|
||||
- Use the `Result` return value from `handle.join()` to get access to the
|
||||
returned value.
|
||||
|
||||
- Ok, what about the other case?
|
||||
- Trigger a panic in the thread. Note that this doesn't panic `main`.
|
||||
- Access the panic payload. This is a good time to talk about [`Any`].
|
||||
|
||||
- Now we can return values from threads! What about taking inputs?
|
||||
- Capture something by reference in the thread closure.
|
||||
- An error message indicates we must move it.
|
||||
- Move it in, see we can compute and then return a derived value.
|
||||
|
||||
- If we want to borrow?
|
||||
- Main kills child threads when it returns, but another function would just
|
||||
return and leave them running.
|
||||
- That would be stack use-after-return, which violates memory safety!
|
||||
- How do we avoid this? see next slide.
|
||||
|
||||
[`Any`]: https://doc.rust-lang.org/std/any/index.html
|
||||
[`thread::spawn`]: https://doc.rust-lang.org/std/thread/fn.spawn.html
|
||||
[`.join()`]: https://doc.rust-lang.org/std/thread/struct.JoinHandle.html#method.join
|
||||
|
||||
</details>
|
||||
{{%segment outline}}
|
||||
|
||||
Reference in New Issue
Block a user