Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

concurrency: Add detailed teaching notes for welcome and threads slides #1885

Merged
merged 2 commits into from
Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions src/concurrency.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,13 @@ channels.
The Rust type system plays an important role in making many concurrency bugs
compile time bugs. This is often referred to as _fearless concurrency_ since you
can rely on the compiler to ensure correctness at runtime.

<details>

- Rust lets us access OS concurrency toolkit: threads, sync. primitives, etc.
- The type system gives us safety for concurrency without any special features.
- The same tools that help with "concurrent" access in a single thread (e.g., a
called function that might mutate an argument or save references to it to read
later) save us from multi-threading issues.

</details>
43 changes: 36 additions & 7 deletions src/concurrency/threads.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,48 @@ fn main() {

<details>

Key points:
- Rust thread APIs look not too different from e.g. C++ ones.

- Notice that the thread is stopped before it reaches 10 --- the main thread is
not waiting.
- 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.
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`].

- Trigger a panic in the thread, notice how this doesn't affect `main`.
- 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.

- Use the `Result` return value from `handle.join()` to get access to the panic
payload. This is a good time to talk about [`Any`].
- 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>
Loading