From face5af783ba646b8871e4d778fcfe27a44f2926 Mon Sep 17 00:00:00 2001 From: "Dustin J. Mitchell" Date: Tue, 23 Apr 2024 09:26:41 -0400 Subject: [PATCH] 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 :) --- Cargo.lock | 20 ++--- Cargo.toml | 4 +- book.toml | 62 +++++++++++---- mdbook-course/src/replacements.rs | 4 +- src/SUMMARY.md | 62 ++++++++------- src/async/control-flow.md | 7 -- src/concurrency/async-control-flow.md | 3 + .../async-control-flow}/channels.md | 4 + .../async-control-flow}/join.md | 4 + .../async-control-flow}/select.md | 4 + src/concurrency/async-exercises.md | 3 + src/concurrency/async-exercises/afternoon.md | 1 + .../async-exercises}/chat-app.md | 4 + .../async-exercises}/chat-async/Cargo.toml | 0 .../chat-async/src/bin/client.rs | 0 .../chat-async/src/bin/server.rs | 0 .../async-exercises/dining-philosophers.md} | 14 ++-- .../async-exercises/dining-philosophers.rs} | 0 .../async-exercises/solutions.md} | 12 +-- .../async-pitfalls.md} | 9 +-- .../async-pitfalls}/async-traits.md | 4 + .../async-pitfalls}/blocking-executor.md | 4 + .../async-pitfalls}/cancellation.md | 4 + .../async-pitfalls}/pin.md | 4 + src/concurrency/async.md | 3 + src/{ => concurrency}/async/async-await.md | 4 + src/{ => concurrency}/async/futures.md | 4 + src/{ => concurrency}/async/runtimes.md | 4 + src/{ => concurrency}/async/runtimes/tokio.md | 0 src/{ => concurrency}/async/tasks.md | 4 + src/concurrency/channels.md | 31 +------- src/concurrency/channels/bounded.md | 4 + src/concurrency/channels/senders-receivers.md | 36 +++++++++ src/concurrency/channels/unbounded.md | 4 + src/concurrency/send-sync.md | 24 +----- src/concurrency/send-sync/examples.md | 4 + src/concurrency/send-sync/marker-traits.md | 29 +++++++ src/concurrency/send-sync/send.md | 4 + src/concurrency/send-sync/sync.md | 4 + src/concurrency/shared-state.md | 3 + .../{shared_state => shared-state}/arc.md | 4 + .../{shared_state => shared-state}/example.md | 4 + .../{shared_state => shared-state}/mutex.md | 4 + src/concurrency/shared_state.md | 11 --- src/concurrency/sync-exercises.md | 3 + .../sync-exercises}/Cargo.toml | 6 +- .../sync-exercises}/dining-philosophers.md | 4 + .../sync-exercises}/dining-philosophers.rs | 0 .../sync-exercises}/link-checker.md | 4 + .../sync-exercises}/link-checker.rs | 0 .../sync-exercises/solutions.md} | 10 +-- src/concurrency/threads.md | 73 +---------------- src/concurrency/threads/plain.md | 78 +++++++++++++++++++ .../{scoped-threads.md => threads/scoped.md} | 4 + .../welcome-async.md} | 7 +- .../welcome.md} | 5 ++ src/exercises/concurrency/afternoon.md | 17 ---- src/running-the-course/course-structure.md | 2 + 58 files changed, 385 insertions(+), 246 deletions(-) delete mode 100644 src/async/control-flow.md create mode 100644 src/concurrency/async-control-flow.md rename src/{async => concurrency/async-control-flow}/channels.md (98%) rename src/{async/control-flow => concurrency/async-control-flow}/join.md (98%) rename src/{async/control-flow => concurrency/async-control-flow}/select.md (99%) create mode 100644 src/concurrency/async-exercises.md create mode 100644 src/concurrency/async-exercises/afternoon.md rename src/{exercises/concurrency => concurrency/async-exercises}/chat-app.md (99%) rename src/{exercises/concurrency => concurrency/async-exercises}/chat-async/Cargo.toml (100%) rename src/{exercises/concurrency => concurrency/async-exercises}/chat-async/src/bin/client.rs (100%) rename src/{exercises/concurrency => concurrency/async-exercises}/chat-async/src/bin/server.rs (100%) rename src/{exercises/concurrency/dining-philosophers-async.md => concurrency/async-exercises/dining-philosophers.md} (78%) rename src/{exercises/concurrency/dining-philosophers-async.rs => concurrency/async-exercises/dining-philosophers.rs} (100%) rename src/{exercises/concurrency/solutions-afternoon.md => concurrency/async-exercises/solutions.md} (63%) rename src/{async/pitfalls.md => concurrency/async-pitfalls.md} (51%) rename src/{async/pitfalls => concurrency/async-pitfalls}/async-traits.md (99%) rename src/{async/pitfalls => concurrency/async-pitfalls}/blocking-executor.md (98%) rename src/{async/pitfalls => concurrency/async-pitfalls}/cancellation.md (99%) rename src/{async/pitfalls => concurrency/async-pitfalls}/pin.md (99%) create mode 100644 src/concurrency/async.md rename src/{ => concurrency}/async/async-await.md (98%) rename src/{ => concurrency}/async/futures.md (98%) rename src/{ => concurrency}/async/runtimes.md (98%) rename src/{ => concurrency}/async/runtimes/tokio.md (100%) rename src/{ => concurrency}/async/tasks.md (98%) create mode 100644 src/concurrency/channels/senders-receivers.md create mode 100644 src/concurrency/send-sync/marker-traits.md create mode 100644 src/concurrency/shared-state.md rename src/concurrency/{shared_state => shared-state}/arc.md (98%) rename src/concurrency/{shared_state => shared-state}/example.md (98%) rename src/concurrency/{shared_state => shared-state}/mutex.md (98%) delete mode 100644 src/concurrency/shared_state.md create mode 100644 src/concurrency/sync-exercises.md rename src/{exercises => concurrency/sync-exercises}/Cargo.toml (72%) rename src/{exercises/concurrency => concurrency/sync-exercises}/dining-philosophers.md (98%) rename src/{exercises/concurrency => concurrency/sync-exercises}/dining-philosophers.rs (100%) rename src/{exercises/concurrency => concurrency/sync-exercises}/link-checker.md (99%) rename src/{exercises/concurrency => concurrency/sync-exercises}/link-checker.rs (100%) rename src/{exercises/concurrency/solutions-morning.md => concurrency/sync-exercises/solutions.md} (58%) create mode 100644 src/concurrency/threads/plain.md rename src/concurrency/{scoped-threads.md => threads/scoped.md} (97%) rename src/{async.md => concurrency/welcome-async.md} (94%) rename src/{concurrency.md => concurrency/welcome.md} (93%) delete mode 100644 src/exercises/concurrency/afternoon.md diff --git a/Cargo.lock b/Cargo.lock index d286efeb..960b7ffb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -322,16 +322,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" -[[package]] -name = "comprehensive-rust" -version = "0.1.0" -dependencies = [ - "reqwest", - "scraper", - "tempfile", - "thiserror", -] - [[package]] name = "control-flow-basics" version = "0.1.0" @@ -2412,6 +2402,16 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync-exercises" +version = "0.1.0" +dependencies = [ + "reqwest", + "scraper", + "tempfile", + "thiserror", +] + [[package]] name = "sync_wrapper" version = "0.1.2" diff --git a/Cargo.toml b/Cargo.toml index bf9c6bea..3a12574a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,8 +9,8 @@ members = [ "src/borrowing", "src/control-flow-basics", "src/error-handling", - "src/exercises", - "src/exercises/concurrency/chat-async", + "src/concurrency/sync-exercises", + "src/concurrency/async-exercises/chat-async", "src/generics", "src/iterators", "src/lifetimes", diff --git a/book.toml b/book.toml index 6478bc3f..e75c6ee5 100644 --- a/book.toml +++ b/book.toml @@ -76,13 +76,26 @@ use-boolean-and = true # # Please keep the table sorted and avoid multi-step redirects. [output.html.redirect] -"tuples-and-arrays/tuples-and-arrays.html" = "tuples.html" +"async/async-await.html" = "../concurrency/async/async-await.html" +"async/channels.html" = "../concurrency/async-control-flow/channels.html" "async/concurrency/channels.html" = "../channels.html" -"async/pitfall/async-traits.html" = "../pitfalls/async-traits.html" -"basic-syntax.html" = "control-flow-basics.html" +"async/control-flow/join.html" = "../concurrency/async-control-flow/join.html" +"async/control-flow/select.html" = "../concurrency/async-control-flow/select.html" +"async/futures.html" = "../concurrency/async/futures.html" +"async.html" = "concurrency/welcome-async.html" +"async/pitfall/async-traits.html" = "../async-pitfalls/async-traits.html" +"async/pitfalls/async-traits.html" = "../concurrency/async-pitfalls/async-traits.html" +"async/pitfalls/blocking-executor.html" = "../concurrency/async-pitfalls/blocking-executor.html" +"async/pitfalls/cancellation.html" = "../concurrency/async-pitfalls/cancellation.html" +"async/pitfalls.html" = "../concurrency/async-pitfalls.html" +"async/pitfalls/pin.html" = "../concurrency/async-pitfalls/pin.html" +"async/runtimes.html" = "../concurrency/async/runtimes.html" +"async/runtimes/tokio.html" = "../concurrency/async/runtimes/tokio.html" +"async/tasks.html" = "../concurrency/async/tasks.html" "basic-syntax/compound-types.html" = "../tuples-and-arrays/tuples-and-arrays.html" -"basic-syntax/functions-interlude.html" = "../control-flow-basics/functions.html" "basic-syntax/functions.html" = "../control-flow-basics/functions.html" +"basic-syntax/functions-interlude.html" = "../control-flow-basics/functions.html" +"basic-syntax.html" = "control-flow-basics.html" "basic-syntax/methods.html" = "../control-flow-basics/functions.html" "basic-syntax/references-dangling.html" = "../references/shared.html" "basic-syntax/references.html" = "../references/shared.html" @@ -94,11 +107,17 @@ use-boolean-and = true "basic-syntax/string-slices.html" = "../references/strings.html" "basic-syntax/type-inference.html" = "../types-and-values/inference.html" "basic-syntax/variables.html" = "../types-and-values/variables.html" +"concurrency.html" = "concurrency/welcome.html" +"concurrency/scoped-threads.html" = "threads/scoped.html" +"concurrency/shared_state/arc.html" = "../shared-state/arc.html" +"concurrency/shared_state/example.html" = "../shared-state/example.html" +"concurrency/shared_state.html" = "shared-state.html" +"concurrency/shared_state/mutex.html" = "../shared-state/mutex.html" "control-flow-basics/conditionals.html" = "if.html" -"control-flow.html" = "control-flow-basics.html" "control-flow/blocks.html" = "../control-flow-basics/blocks-and-scopes.html" "control-flow/break-continue.html" = "../control-flow-basics/break-continue.html" "control-flow/for-expressions.html" = "../control-flow-basics/loops.html" +"control-flow.html" = "control-flow-basics.html" "control-flow/if-expressions.html" = "../control-flow-basics/conditionals.html" "control-flow/if-let-expressions.html" = "../pattern-matching/let-control-flow.html" "control-flow/loop-expressions.html" = "../control-flow-basics/loops.html" @@ -118,7 +137,15 @@ use-boolean-and = true "error-handling/panic-unwind.html" = "../error-handling/panics.html" "error-handling/result.html" = "../std-types/result.html" "error-handling/try-operator.html" = "../error-handling/try.html" +"exercises/concurrency/afternoon.html" = "../../concurrency/async-exercises.html" +"exercises/concurrency/chat-app.html" = "../../concurrency/async-exercises/chat-app.html" +"exercises/concurrency/dining-philosophers-async.html" = "../../concurrency/async-exercises/dining-philosophers.html" +"exercises/concurrency/dining-philosophers.html" = "../../concurrency/sync-exercises/dining-philosophers.html" "exercises/concurrency/elevator.html" = "chat-app.html" +"exercises/concurrency/link-checker.html" = "../../concurrency/sync-exercises/link-checker.html" +"exercises/concurrency/morning.html" = "../../concurrency/sync-exercises.html" +"exercises/concurrency/solutions-afternoon.html" = "../../concurrency/async-exercises/solutions.html" +"exercises/concurrency/solutions-morning.html" = "../../concurrency/sync-exercises/solutions.html" "exercises/day-1/afternoon.html" = "../../control-flow-basics/exercise.html" "exercises/day-1/book-library.html" = "../day-2/book-library.html" "exercises/day-1/for-loops.html" = "../../tuples-and-arrays/exercise.html" @@ -161,22 +188,22 @@ use-boolean-and = true "memory-management/manual.html" = "../memory-management/approaches.html" "memory-management/rust.html" = "../memory-management/ownership.html" "memory-management/scope-based.html" = "../memory-management/approaches.html" -"memory-management/stack-vs-heap.html" = "../memory-management/review.html" "memory-management/stack.html" = "../memory-management/review.html" +"memory-management/stack-vs-heap.html" = "../memory-management/review.html" "methods-and-traits/trait-objects.html" = "../smart-pointers/trait-objects.html" -"methods.html" = "methods-and-traits/methods.html" "methods/example.html" = "../methods-and-traits/methods.html" +"methods.html" = "methods-and-traits/methods.html" "methods/receiver.html" = "../methods-and-traits/methods.html" "outros-recursos.html" = "other-resources.html" -"ownership.html" = "memory-management/ownership.html" "ownership/borrowing.html" = "../borrowing/shared.html" "ownership/copy-clone.html" = "../memory-management/copy-types.html" "ownership/double-free-modern-cpp.html" = "../memory-management/move.html" +"ownership.html" = "memory-management/ownership.html" "ownership/lifetimes-data-structures.html" = "../lifetimes/struct-lifetimes.html" "ownership/lifetimes-function-calls.html" = "../lifetimes/lifetime-elision.html" "ownership/lifetimes.html" = "../lifetimes/lifetime-annotations.html" -"ownership/move-semantics.html" = "../memory-management/move.html" "ownership/moved-strings-rust.html" = "../memory-management/move.html" +"ownership/move-semantics.html" = "../memory-management/move.html" "ownership/moves-function-calls.html" = "../memory-management/move.html" "ownership/shared-unique-borrows.html" = "../borrowing/shared.html" "pattern-matching/destructuring-arrays.html" = "../tuples-and-arrays/destructuring.html" @@ -185,26 +212,26 @@ use-boolean-and = true "pattern-matching/match-guards.html" = "../tuples-and-arrays/match.html" "running-the-course/day-4.html" = "course-structure.html" "sintaxe-básica/funções-interlude.html" = "../basic-syntax/functions-interlude.html" -"slices-and-lifetimes.html" = "lifetimes.html" "slices-and-lifetimes/exercise.html" = "../lifetimes/exercise.html" +"slices-and-lifetimes.html" = "lifetimes.html" "slices-and-lifetimes/lifetime-annotations.html" = "../lifetimes/lifetime-annotations.html" "slices-and-lifetimes/lifetime-elision.html" = "../lifetimes/lifetime-elision.html" "slices-and-lifetimes/slices.html" = "../references/slices.html" "slices-and-lifetimes/solution.html" = "../lifetimes/solution.html" "slices-and-lifetimes/str.html" = "../references/strings.html" "slices-and-lifetimes/struct-lifetimes.html" = "../lifetimes/struct-lifetimes.html" -"std.html" = "std-types/std.html" +"std/box.html" = "../smart-pointers/box.html" "std/box-niche.html" = "../smart-pointers/box.html" "std/box-recursive.html" = "../smart-pointers/box.html" -"std/box.html" = "../smart-pointers/box.html" "std/cell.html" = "../borrowing/interior-mutability.html" "std/hashmap.html" = "../std-types/hashmap.html" +"std.html" = "std-types/std.html" "std/option-result.html" = "../std-types/option.html" "std/rc.html" = "../smart-pointers/rc.html" "std/string.html" = "../std-types/string.html" "std/vec.html" = "../std-types/vec.html" -"structs.html" = "user-defined-types/named-structs.html" "structs/field-shorthand.html" = "../user-defined-types/named-structs.html" +"structs.html" = "user-defined-types/named-structs.html" "structs/tuple-structs.html" = "../user-defined-types/tuple-structs.html" "structure.html" = "running-the-course/course-structure.html" "testing/doc-tests.html" = "../testing/other.html" @@ -212,14 +239,14 @@ use-boolean-and = true "testing/integration-tests.html" = "../testing/other.html" "testing/mockall.html" = "../android/testing/mockall.html" "testing/useful-crates.html" = "../testing.html" -"traits.html" = "methods-and-traits/traits.html" "traits/closures.html" = "../std-traits/closures.html" -"traits/default-methods.html" = "../methods-and-traits/traits.html" "traits/default.html" = "../std-traits/default.html" +"traits/default-methods.html" = "../methods-and-traits/traits.html" "traits/deriving-traits.html" = "../methods-and-traits/deriving.html" "traits/drop.html" = "../memory-management/drop.html" "traits/from-into.html" = "../std-traits/from-and-into.html" "traits/from-iterator.html" = "../iterators/fromiterator.html" +"traits.html" = "methods-and-traits/traits.html" "traits/impl-trait.html" = "../generics/impl-trait.html" "traits/important-traits.html" = "../std-traits/comparisons.html" "traits/iterator.html" = "../iterators/iterators.html" @@ -228,10 +255,11 @@ use-boolean-and = true "traits/trait-bounds.html" = "../generics/trait-bounds.html" "traits/trait-objects.html" = "../smart-pointers/trait-objects.html" "tuples-and-arrays/match.html" = "../pattern-matching/match.html" +"tuples-and-arrays/tuples-and-arrays.html" = "tuples.html" "types-and-values/strings.html" = "../references/strings.html" -"unsafe.html" = "unsafe-rust/unsafe.html" "unsafe/calling-unsafe-functions.html" = "../unsafe-rust/unsafe-functions.html" "unsafe/extern-functions.html" = "../unsafe-rust/unsafe-functions.html" +"unsafe.html" = "unsafe-rust/unsafe.html" "unsafe/mutable-static-variables.html" = "../unsafe-rust/mutable-static.html" "unsafe/mutable-static-variables.md" = "mutable-static-variables.html" "unsafe/raw-pointers.html" = "../unsafe-rust/dereferencing.html" @@ -243,9 +271,9 @@ use-boolean-and = true "welcome-bare-metal.html" = "bare-metal.html" "welcome-day-1/what-is-rust.html" = "../hello-world/what-is-rust.html" "welcome.html" = "./" -"why-rust.html" = "hello-world/benefits.html" "why-rust/an-example-in-c.html" = "../hello-world/example.html" "why-rust/compile-time.html" = "../hello-world/benefits.html" +"why-rust.html" = "hello-world/benefits.html" "why-rust/modern.html" = "../hello-world/benefits.html" "why-rust/runtime.html" = "../hello-world/benefits.html" diff --git a/mdbook-course/src/replacements.rs b/mdbook-course/src/replacements.rs index dda51384..3695aa79 100644 --- a/mdbook-course/src/replacements.rs +++ b/mdbook-course/src/replacements.rs @@ -35,7 +35,7 @@ pub fn replace( return; }; chapter.content = DIRECTIVE - .replace(&chapter.content, |captures: ®ex::Captures| { + .replace_all(&chapter.content, |captures: ®ex::Captures| { let directive_str = captures[1].trim(); let directive: Vec<_> = directive_str.split_whitespace().collect(); match directive.as_slice() { @@ -50,7 +50,7 @@ pub fn replace( } ["course", "outline", course_name] => { let Some(course) = courses.find_course(course_name) else { - return captures[0].to_string(); + return format!("not found - {}", captures[0].to_string()); }; course.schedule() } diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 734208de..42d9cfac 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -353,46 +353,50 @@ --- -- [Welcome](concurrency.md) +- [Welcome](concurrency/welcome.md) - [Threads](concurrency/threads.md) - - [Scoped Threads](concurrency/scoped-threads.md) + - [Plain Threads](concurrency/threads/plain.md) + - [Scoped Threads](concurrency/threads/scoped.md) - [Channels](concurrency/channels.md) + - [Senders and Reveivers](concurrency/channels/senders-receivers.md) - [Unbounded Channels](concurrency/channels/unbounded.md) - [Bounded Channels](concurrency/channels/bounded.md) - [`Send` and `Sync`](concurrency/send-sync.md) + - [Marker Traits](concurrency/send-sync/marker-traits.md) - [`Send`](concurrency/send-sync/send.md) - [`Sync`](concurrency/send-sync/sync.md) - [Examples](concurrency/send-sync/examples.md) -- [Shared State](concurrency/shared_state.md) - - [`Arc`](concurrency/shared_state/arc.md) - - [`Mutex`](concurrency/shared_state/mutex.md) - - [Example](concurrency/shared_state/example.md) -- [Exercises](exercises/concurrency/morning.md) - - [Dining Philosophers](exercises/concurrency/dining-philosophers.md) - - [Multi-threaded Link Checker](exercises/concurrency/link-checker.md) - - [Solutions](exercises/concurrency/solutions-morning.md) +- [Shared State](concurrency/shared-state.md) + - [`Arc`](concurrency/shared-state/arc.md) + - [`Mutex`](concurrency/shared-state/mutex.md) + - [Example](concurrency/shared-state/example.md) +- [Exercises](concurrency/sync-exercises.md) + - [Dining Philosophers](concurrency/sync-exercises/dining-philosophers.md) + - [Multi-threaded Link Checker](concurrency/sync-exercises/link-checker.md) + - [Solutions](concurrency/sync-exercises/solutions.md) # Concurrency: Afternoon -- [Async Basics](async.md) - - [`async`/`await`](async/async-await.md) - - [Futures](async/futures.md) - - [Runtimes](async/runtimes.md) - - [Tokio](async/runtimes/tokio.md) - - [Tasks](async/tasks.md) - - [Async Channels](async/channels.md) -- [Control Flow](async/control-flow.md) - - [Join](async/control-flow/join.md) - - [Select](async/control-flow/select.md) -- [Pitfalls](async/pitfalls.md) - - [Blocking the Executor](async/pitfalls/blocking-executor.md) - - [`Pin`](async/pitfalls/pin.md) - - [Async Traits](async/pitfalls/async-traits.md) - - [Cancellation](async/pitfalls/cancellation.md) -- [Exercises](exercises/concurrency/afternoon.md) - - [Dining Philosophers](exercises/concurrency/dining-philosophers-async.md) - - [Broadcast Chat Application](exercises/concurrency/chat-app.md) - - [Solutions](exercises/concurrency/solutions-afternoon.md) +- [Welcome](concurrency/welcome-async.md) +- [Async Basics](concurrency/async.md) + - [`async`/`await`](concurrency/async/async-await.md) + - [Futures](concurrency/async/futures.md) + - [Runtimes](concurrency/async/runtimes.md) + - [Tokio](concurrency/async/runtimes/tokio.md) + - [Tasks](concurrency/async/tasks.md) +- [Channels and Control Flow](concurrency/async-control-flow.md) + - [Async Channels](concurrency/async-control-flow/channels.md) + - [Join](concurrency/async-control-flow/join.md) + - [Select](concurrency/async-control-flow/select.md) +- [Pitfalls](concurrency/async-pitfalls.md) + - [Blocking the Executor](concurrency/async-pitfalls/blocking-executor.md) + - [`Pin`](concurrency/async-pitfalls/pin.md) + - [Async Traits](concurrency/async-pitfalls/async-traits.md) + - [Cancellation](concurrency/async-pitfalls/cancellation.md) +- [Exercises](concurrency/async-exercises.md) + - [Dining Philosophers](concurrency/async-exercises/dining-philosophers.md) + - [Broadcast Chat Application](concurrency/async-exercises/chat-app.md) + - [Solutions](concurrency/async-exercises/solutions.md) # Final Words diff --git a/src/async/control-flow.md b/src/async/control-flow.md deleted file mode 100644 index 69b1d03e..00000000 --- a/src/async/control-flow.md +++ /dev/null @@ -1,7 +0,0 @@ -# Futures Control Flow - -Futures can be combined together to produce concurrent compute flow graphs. We -have already seen tasks, that function as independent threads of execution. - -- [Join](control-flow/join.md) -- [Select](control-flow/select.md) diff --git a/src/concurrency/async-control-flow.md b/src/concurrency/async-control-flow.md new file mode 100644 index 00000000..4b015cec --- /dev/null +++ b/src/concurrency/async-control-flow.md @@ -0,0 +1,3 @@ +# Channels and Control Flow + +{{%segment outline}} diff --git a/src/async/channels.md b/src/concurrency/async-control-flow/channels.md similarity index 98% rename from src/async/channels.md rename to src/concurrency/async-control-flow/channels.md index 301c0ab2..72678464 100644 --- a/src/async/channels.md +++ b/src/concurrency/async-control-flow/channels.md @@ -1,3 +1,7 @@ +--- +minutes: 8 +--- + # Async Channels Several crates have support for asynchronous channels. For instance `tokio`: diff --git a/src/async/control-flow/join.md b/src/concurrency/async-control-flow/join.md similarity index 98% rename from src/async/control-flow/join.md rename to src/concurrency/async-control-flow/join.md index 0d1015e8..6aa06e6d 100644 --- a/src/async/control-flow/join.md +++ b/src/concurrency/async-control-flow/join.md @@ -1,3 +1,7 @@ +--- +minutes: 4 +--- + # Join A join operation waits until all of a set of futures are ready, and returns a diff --git a/src/async/control-flow/select.md b/src/concurrency/async-control-flow/select.md similarity index 99% rename from src/async/control-flow/select.md rename to src/concurrency/async-control-flow/select.md index b354dccd..b3df5c2f 100644 --- a/src/async/control-flow/select.md +++ b/src/concurrency/async-control-flow/select.md @@ -1,3 +1,7 @@ +--- +minutes: 5 +--- + # Select A select operation waits until any of a set of futures is ready, and responds to diff --git a/src/concurrency/async-exercises.md b/src/concurrency/async-exercises.md new file mode 100644 index 00000000..c2ae9b75 --- /dev/null +++ b/src/concurrency/async-exercises.md @@ -0,0 +1,3 @@ +# Exercises + +{{%segment outline}} diff --git a/src/concurrency/async-exercises/afternoon.md b/src/concurrency/async-exercises/afternoon.md new file mode 100644 index 00000000..eba3257d --- /dev/null +++ b/src/concurrency/async-exercises/afternoon.md @@ -0,0 +1 @@ +# Exercises diff --git a/src/exercises/concurrency/chat-app.md b/src/concurrency/async-exercises/chat-app.md similarity index 99% rename from src/exercises/concurrency/chat-app.md rename to src/concurrency/async-exercises/chat-app.md index 95eee6e2..1fc9bddb 100644 --- a/src/exercises/concurrency/chat-app.md +++ b/src/concurrency/async-exercises/chat-app.md @@ -1,3 +1,7 @@ +--- +minutes: 30 +--- + # Broadcast Chat Application In this exercise, we want to use our new knowledge to implement a broadcast chat diff --git a/src/exercises/concurrency/chat-async/Cargo.toml b/src/concurrency/async-exercises/chat-async/Cargo.toml similarity index 100% rename from src/exercises/concurrency/chat-async/Cargo.toml rename to src/concurrency/async-exercises/chat-async/Cargo.toml diff --git a/src/exercises/concurrency/chat-async/src/bin/client.rs b/src/concurrency/async-exercises/chat-async/src/bin/client.rs similarity index 100% rename from src/exercises/concurrency/chat-async/src/bin/client.rs rename to src/concurrency/async-exercises/chat-async/src/bin/client.rs diff --git a/src/exercises/concurrency/chat-async/src/bin/server.rs b/src/concurrency/async-exercises/chat-async/src/bin/server.rs similarity index 100% rename from src/exercises/concurrency/chat-async/src/bin/server.rs rename to src/concurrency/async-exercises/chat-async/src/bin/server.rs diff --git a/src/exercises/concurrency/dining-philosophers-async.md b/src/concurrency/async-exercises/dining-philosophers.md similarity index 78% rename from src/exercises/concurrency/dining-philosophers-async.md rename to src/concurrency/async-exercises/dining-philosophers.md index fee6ef0d..a1d783cc 100644 --- a/src/exercises/concurrency/dining-philosophers-async.md +++ b/src/concurrency/async-exercises/dining-philosophers.md @@ -1,3 +1,7 @@ +--- +minutes: 20 +--- + # Dining Philosophers --- Async See [dining philosophers](dining-philosophers.md) for a description of the @@ -11,17 +15,17 @@ code below to a file called `src/main.rs`, fill out the blanks, and test that ```rust,compile_fail -{{#include dining-philosophers-async.rs:Philosopher}} +{{#include dining-philosophers.rs:Philosopher}} // left_fork: ... // right_fork: ... // thoughts: ... } -{{#include dining-philosophers-async.rs:Philosopher-think}} +{{#include dining-philosophers.rs:Philosopher-think}} -{{#include dining-philosophers-async.rs:Philosopher-eat}} -{{#include dining-philosophers-async.rs:Philosopher-eat-body}} -{{#include dining-philosophers-async.rs:Philosopher-eat-end}} +{{#include dining-philosophers.rs:Philosopher-eat}} +{{#include dining-philosophers.rs:Philosopher-eat-body}} +{{#include dining-philosophers.rs:Philosopher-eat-end}} // Create forks // Create philosophers diff --git a/src/exercises/concurrency/dining-philosophers-async.rs b/src/concurrency/async-exercises/dining-philosophers.rs similarity index 100% rename from src/exercises/concurrency/dining-philosophers-async.rs rename to src/concurrency/async-exercises/dining-philosophers.rs diff --git a/src/exercises/concurrency/solutions-afternoon.md b/src/concurrency/async-exercises/solutions.md similarity index 63% rename from src/exercises/concurrency/solutions-afternoon.md rename to src/concurrency/async-exercises/solutions.md index b9ff308c..82ed49e3 100644 --- a/src/exercises/concurrency/solutions-afternoon.md +++ b/src/concurrency/async-exercises/solutions.md @@ -1,17 +1,17 @@ -# Concurrency Afternoon Exercise +--- +minutes: 20 +--- + +# Solutions ## Dining Philosophers --- Async -([back to exercise](dining-philosophers-async.md)) - ```rust,compile_fail -{{#include dining-philosophers-async.rs:solution}} +{{#include dining-philosophers.rs:solution}} ``` ## Broadcast Chat Application -([back to exercise](chat-app.md)) - _src/bin/server.rs_: ```rust,compile_fail diff --git a/src/async/pitfalls.md b/src/concurrency/async-pitfalls.md similarity index 51% rename from src/async/pitfalls.md rename to src/concurrency/async-pitfalls.md index 924c9c1c..ff1b750e 100644 --- a/src/async/pitfalls.md +++ b/src/concurrency/async-pitfalls.md @@ -1,10 +1,7 @@ -# Pitfalls of async/await +# Pitfalls Async / await provides convenient and efficient abstraction for concurrent asynchronous programming. However, the async/await model in Rust also comes with -its share of pitfalls and footguns. We illustrate some of them in this chapter: +its share of pitfalls and footguns. We illustrate some of them in this chapter. -- [Blocking the Executor](pitfalls/blocking-executor.md) -- [Pin](pitfalls/pin.md) -- [Async Traits](pitfalls/async-traits.md) -- [Cancellation](pitfalls/cancellation.md) +{{%segment outline}} diff --git a/src/async/pitfalls/async-traits.md b/src/concurrency/async-pitfalls/async-traits.md similarity index 99% rename from src/async/pitfalls/async-traits.md rename to src/concurrency/async-pitfalls/async-traits.md index a9f0b31a..5b285ec1 100644 --- a/src/async/pitfalls/async-traits.md +++ b/src/concurrency/async-pitfalls/async-traits.md @@ -1,3 +1,7 @@ +--- +minutes: 5 +--- + # Async Traits Async methods in traits are were stabilized only recently, in the 1.75 release. diff --git a/src/async/pitfalls/blocking-executor.md b/src/concurrency/async-pitfalls/blocking-executor.md similarity index 98% rename from src/async/pitfalls/blocking-executor.md rename to src/concurrency/async-pitfalls/blocking-executor.md index 2ec6d1fb..d2fe9635 100644 --- a/src/async/pitfalls/blocking-executor.md +++ b/src/concurrency/async-pitfalls/blocking-executor.md @@ -1,3 +1,7 @@ +--- +minutes: 10 +--- + # Blocking the executor Most async runtimes only allow IO tasks to run concurrently. This means that CPU diff --git a/src/async/pitfalls/cancellation.md b/src/concurrency/async-pitfalls/cancellation.md similarity index 99% rename from src/async/pitfalls/cancellation.md rename to src/concurrency/async-pitfalls/cancellation.md index 6b18bf02..66fae4e6 100644 --- a/src/async/pitfalls/cancellation.md +++ b/src/concurrency/async-pitfalls/cancellation.md @@ -1,3 +1,7 @@ +--- +minutes: 18 +--- + # Cancellation Dropping a future implies it can never be polled again. This is called diff --git a/src/async/pitfalls/pin.md b/src/concurrency/async-pitfalls/pin.md similarity index 99% rename from src/async/pitfalls/pin.md rename to src/concurrency/async-pitfalls/pin.md index 2bdd8225..fc764a8a 100644 --- a/src/async/pitfalls/pin.md +++ b/src/concurrency/async-pitfalls/pin.md @@ -1,3 +1,7 @@ +--- +minutes: 20 +--- + # `Pin` Async blocks and functions return types implementing the `Future` trait. The diff --git a/src/concurrency/async.md b/src/concurrency/async.md new file mode 100644 index 00000000..8f37e021 --- /dev/null +++ b/src/concurrency/async.md @@ -0,0 +1,3 @@ +# Async Basics + +{{%segment outline}} diff --git a/src/async/async-await.md b/src/concurrency/async/async-await.md similarity index 98% rename from src/async/async-await.md rename to src/concurrency/async/async-await.md index b80d19b4..9248cb39 100644 --- a/src/async/async-await.md +++ b/src/concurrency/async/async-await.md @@ -1,3 +1,7 @@ +--- +minutes: 6 +--- + # `async`/`await` At a high level, async Rust code looks very much like "normal" sequential code: diff --git a/src/async/futures.md b/src/concurrency/async/futures.md similarity index 98% rename from src/async/futures.md rename to src/concurrency/async/futures.md index 60b38b78..9e1b2b52 100644 --- a/src/async/futures.md +++ b/src/concurrency/async/futures.md @@ -1,3 +1,7 @@ +--- +minutes: 4 +--- + # Futures [`Future`](https://doc.rust-lang.org/std/future/trait.Future.html) is a trait, diff --git a/src/async/runtimes.md b/src/concurrency/async/runtimes.md similarity index 98% rename from src/async/runtimes.md rename to src/concurrency/async/runtimes.md index 6b03541b..aae19665 100644 --- a/src/async/runtimes.md +++ b/src/concurrency/async/runtimes.md @@ -1,3 +1,7 @@ +--- +minutes: 10 +--- + # Runtimes A _runtime_ provides support for performing operations asynchronously (a diff --git a/src/async/runtimes/tokio.md b/src/concurrency/async/runtimes/tokio.md similarity index 100% rename from src/async/runtimes/tokio.md rename to src/concurrency/async/runtimes/tokio.md diff --git a/src/async/tasks.md b/src/concurrency/async/tasks.md similarity index 98% rename from src/async/tasks.md rename to src/concurrency/async/tasks.md index 86e1a552..2c23a006 100644 --- a/src/async/tasks.md +++ b/src/concurrency/async/tasks.md @@ -1,3 +1,7 @@ +--- +minutes: 6 +--- + # Tasks Rust has a task system, which is a form of lightweight threading. diff --git a/src/concurrency/channels.md b/src/concurrency/channels.md index b9c86035..618e297a 100644 --- a/src/concurrency/channels.md +++ b/src/concurrency/channels.md @@ -1,32 +1,3 @@ # Channels -Rust channels have two parts: a `Sender` and a `Receiver`. The two parts -are connected via the channel, but you only see the end-points. - -```rust,editable -use std::sync::mpsc; - -fn main() { - let (tx, rx) = mpsc::channel(); - - tx.send(10).unwrap(); - tx.send(20).unwrap(); - - println!("Received: {:?}", rx.recv()); - println!("Received: {:?}", rx.recv()); - - let tx2 = tx.clone(); - tx2.send(30).unwrap(); - println!("Received: {:?}", rx.recv()); -} -``` - -
- -- `mpsc` stands for Multi-Producer, Single-Consumer. `Sender` and `SyncSender` - implement `Clone` (so you can make multiple producers) but `Receiver` does - not. -- `send()` and `recv()` return `Result`. If they return `Err`, it means the - counterpart `Sender` or `Receiver` is dropped and the channel is closed. - -
+{{%segment outline}} diff --git a/src/concurrency/channels/bounded.md b/src/concurrency/channels/bounded.md index 0cb9fe91..e1667d4f 100644 --- a/src/concurrency/channels/bounded.md +++ b/src/concurrency/channels/bounded.md @@ -1,3 +1,7 @@ +--- +minutes: 8 +--- + # Bounded Channels With bounded (synchronous) channels, `send` can block the current thread: diff --git a/src/concurrency/channels/senders-receivers.md b/src/concurrency/channels/senders-receivers.md new file mode 100644 index 00000000..c0ece357 --- /dev/null +++ b/src/concurrency/channels/senders-receivers.md @@ -0,0 +1,36 @@ +--- +minutes: 9 +--- + +# Senders and Receivers + +Rust channels have two parts: a `Sender` and a `Receiver`. The two parts +are connected via the channel, but you only see the end-points. + +```rust,editable +use std::sync::mpsc; + +fn main() { + let (tx, rx) = mpsc::channel(); + + tx.send(10).unwrap(); + tx.send(20).unwrap(); + + println!("Received: {:?}", rx.recv()); + println!("Received: {:?}", rx.recv()); + + let tx2 = tx.clone(); + tx2.send(30).unwrap(); + println!("Received: {:?}", rx.recv()); +} +``` + +
+ +- `mpsc` stands for Multi-Producer, Single-Consumer. `Sender` and `SyncSender` + implement `Clone` (so you can make multiple producers) but `Receiver` does + not. +- `send()` and `recv()` return `Result`. If they return `Err`, it means the + counterpart `Sender` or `Receiver` is dropped and the channel is closed. + +
diff --git a/src/concurrency/channels/unbounded.md b/src/concurrency/channels/unbounded.md index e96220f1..c0664121 100644 --- a/src/concurrency/channels/unbounded.md +++ b/src/concurrency/channels/unbounded.md @@ -1,3 +1,7 @@ +--- +minutes: 2 +--- + # Unbounded Channels You get an unbounded and asynchronous channel with `mpsc::channel()`: diff --git a/src/concurrency/send-sync.md b/src/concurrency/send-sync.md index 2883217a..96990e9f 100644 --- a/src/concurrency/send-sync.md +++ b/src/concurrency/send-sync.md @@ -1,25 +1,3 @@ # `Send` and `Sync` -How does Rust know to forbid shared access across threads? The answer is in two -traits: - -- [`Send`][1]: a type `T` is `Send` if it is safe to move a `T` across a thread - boundary. -- [`Sync`][2]: a type `T` is `Sync` if it is safe to move a `&T` across a thread - boundary. - -`Send` and `Sync` are [unsafe traits][3]. The compiler will automatically derive -them for your types as long as they only contain `Send` and `Sync` types. You -can also implement them manually when you know it is valid. - -[1]: https://doc.rust-lang.org/std/marker/trait.Send.html -[2]: https://doc.rust-lang.org/std/marker/trait.Sync.html -[3]: ../unsafe/unsafe-traits.md - -
- -- One can think of these traits as markers that the type has certain - thread-safety properties. -- They can be used in the generic constraints as normal traits. - -
+{{%segment outline}} diff --git a/src/concurrency/send-sync/examples.md b/src/concurrency/send-sync/examples.md index 1bc78d73..d3074df3 100644 --- a/src/concurrency/send-sync/examples.md +++ b/src/concurrency/send-sync/examples.md @@ -1,3 +1,7 @@ +--- +minutes: 6 +--- + # Examples ## `Send + Sync` diff --git a/src/concurrency/send-sync/marker-traits.md b/src/concurrency/send-sync/marker-traits.md new file mode 100644 index 00000000..cb99591c --- /dev/null +++ b/src/concurrency/send-sync/marker-traits.md @@ -0,0 +1,29 @@ +--- +minutes: 2 +--- + +# Marker Traits + +How does Rust know to forbid shared access across threads? The answer is in two +traits: + +- [`Send`][1]: a type `T` is `Send` if it is safe to move a `T` across a thread + boundary. +- [`Sync`][2]: a type `T` is `Sync` if it is safe to move a `&T` across a thread + boundary. + +`Send` and `Sync` are [unsafe traits][3]. The compiler will automatically derive +them for your types as long as they only contain `Send` and `Sync` types. You +can also implement them manually when you know it is valid. + +[1]: https://doc.rust-lang.org/std/marker/trait.Send.html +[2]: https://doc.rust-lang.org/std/marker/trait.Sync.html +[3]: ../unsafe/unsafe-traits.md + +
+ +- One can think of these traits as markers that the type has certain + thread-safety properties. +- They can be used in the generic constraints as normal traits. + +
diff --git a/src/concurrency/send-sync/send.md b/src/concurrency/send-sync/send.md index 934ab3c5..ab25719f 100644 --- a/src/concurrency/send-sync/send.md +++ b/src/concurrency/send-sync/send.md @@ -1,3 +1,7 @@ +--- +minutes: 2 +--- + # `Send` > A type `T` is [`Send`][1] if it is safe to move a `T` value to another thread. diff --git a/src/concurrency/send-sync/sync.md b/src/concurrency/send-sync/sync.md index ea490bcb..333bb22c 100644 --- a/src/concurrency/send-sync/sync.md +++ b/src/concurrency/send-sync/sync.md @@ -1,3 +1,7 @@ +--- +minutes: 2 +--- + # `Sync` > A type `T` is [`Sync`][1] if it is safe to access a `T` value from multiple diff --git a/src/concurrency/shared-state.md b/src/concurrency/shared-state.md new file mode 100644 index 00000000..73a1119b --- /dev/null +++ b/src/concurrency/shared-state.md @@ -0,0 +1,3 @@ +# Shared State + +{{%segment outline}} diff --git a/src/concurrency/shared_state/arc.md b/src/concurrency/shared-state/arc.md similarity index 98% rename from src/concurrency/shared_state/arc.md rename to src/concurrency/shared-state/arc.md index 9ec310f8..694a6dc2 100644 --- a/src/concurrency/shared_state/arc.md +++ b/src/concurrency/shared-state/arc.md @@ -1,3 +1,7 @@ +--- +minutes: 5 +--- + # `Arc` [`Arc`][1] allows shared read-only access via `Arc::clone`: diff --git a/src/concurrency/shared_state/example.md b/src/concurrency/shared-state/example.md similarity index 98% rename from src/concurrency/shared_state/example.md rename to src/concurrency/shared-state/example.md index 2219b700..180d9f94 100644 --- a/src/concurrency/shared_state/example.md +++ b/src/concurrency/shared-state/example.md @@ -1,3 +1,7 @@ +--- +minutes: 8 +--- + # Example Let us see `Arc` and `Mutex` in action: diff --git a/src/concurrency/shared_state/mutex.md b/src/concurrency/shared-state/mutex.md similarity index 98% rename from src/concurrency/shared_state/mutex.md rename to src/concurrency/shared-state/mutex.md index f9a06284..555ee55f 100644 --- a/src/concurrency/shared_state/mutex.md +++ b/src/concurrency/shared-state/mutex.md @@ -1,3 +1,7 @@ +--- +minutes: 14 +--- + # `Mutex` [`Mutex`][1] ensures mutual exclusion _and_ allows mutable access to `T` diff --git a/src/concurrency/shared_state.md b/src/concurrency/shared_state.md deleted file mode 100644 index de84078a..00000000 --- a/src/concurrency/shared_state.md +++ /dev/null @@ -1,11 +0,0 @@ -# Shared State - -Rust uses the type system to enforce synchronization of shared data. This is -primarily done via two types: - -- [`Arc`][1], atomic reference counted `T`: handles sharing between threads - and takes care to deallocate `T` when the last reference is dropped, -- [`Mutex`][2]: ensures mutually exclusive access to the `T` value. - -[1]: https://doc.rust-lang.org/std/sync/struct.Arc.html -[2]: https://doc.rust-lang.org/std/sync/struct.Mutex.html diff --git a/src/concurrency/sync-exercises.md b/src/concurrency/sync-exercises.md new file mode 100644 index 00000000..c2ae9b75 --- /dev/null +++ b/src/concurrency/sync-exercises.md @@ -0,0 +1,3 @@ +# Exercises + +{{%segment outline}} diff --git a/src/exercises/Cargo.toml b/src/concurrency/sync-exercises/Cargo.toml similarity index 72% rename from src/exercises/Cargo.toml rename to src/concurrency/sync-exercises/Cargo.toml index c646c02d..721de07c 100644 --- a/src/exercises/Cargo.toml +++ b/src/concurrency/sync-exercises/Cargo.toml @@ -1,16 +1,16 @@ [package] -name = "comprehensive-rust" +name = "sync-exercises" version = "0.1.0" edition = "2021" publish = false [[bin]] name = "dining-philosophers" -path = "concurrency/dining-philosophers.rs" +path = "dining-philosophers.rs" [[bin]] name = "link-checker" -path = "concurrency/link-checker.rs" +path = "link-checker.rs" [dependencies] reqwest = { version = "0.12.4", features = ["blocking"] } diff --git a/src/exercises/concurrency/dining-philosophers.md b/src/concurrency/sync-exercises/dining-philosophers.md similarity index 98% rename from src/exercises/concurrency/dining-philosophers.md rename to src/concurrency/sync-exercises/dining-philosophers.md index 98327ae7..d7aa55f7 100644 --- a/src/exercises/concurrency/dining-philosophers.md +++ b/src/concurrency/sync-exercises/dining-philosophers.md @@ -1,3 +1,7 @@ +--- +minutes: 20 +--- + # Dining Philosophers The dining philosophers problem is a classic problem in concurrency: diff --git a/src/exercises/concurrency/dining-philosophers.rs b/src/concurrency/sync-exercises/dining-philosophers.rs similarity index 100% rename from src/exercises/concurrency/dining-philosophers.rs rename to src/concurrency/sync-exercises/dining-philosophers.rs diff --git a/src/exercises/concurrency/link-checker.md b/src/concurrency/sync-exercises/link-checker.md similarity index 99% rename from src/exercises/concurrency/link-checker.md rename to src/concurrency/sync-exercises/link-checker.md index 096aa155..c9248f43 100644 --- a/src/exercises/concurrency/link-checker.md +++ b/src/concurrency/sync-exercises/link-checker.md @@ -1,3 +1,7 @@ +--- +minutes: 20 +--- + # Multi-threaded Link Checker Let us use our new knowledge to create a multi-threaded link checker. It should diff --git a/src/exercises/concurrency/link-checker.rs b/src/concurrency/sync-exercises/link-checker.rs similarity index 100% rename from src/exercises/concurrency/link-checker.rs rename to src/concurrency/sync-exercises/link-checker.rs diff --git a/src/exercises/concurrency/solutions-morning.md b/src/concurrency/sync-exercises/solutions.md similarity index 58% rename from src/exercises/concurrency/solutions-morning.md rename to src/concurrency/sync-exercises/solutions.md index a31c581e..7d8c7583 100644 --- a/src/exercises/concurrency/solutions-morning.md +++ b/src/concurrency/sync-exercises/solutions.md @@ -1,17 +1,17 @@ -# Concurrency Morning Exercise +--- +minutes: 30 +--- + +# Solutions ## Dining Philosophers -([back to exercise](dining-philosophers.md)) - ```rust {{#include dining-philosophers.rs:solution}} ``` ## Link Checker -([back to exercise](link-checker.md)) - ```rust,compile_fail {{#include link-checker.rs:solution}} ``` diff --git a/src/concurrency/threads.md b/src/concurrency/threads.md index 432231c8..f81820e2 100644 --- a/src/concurrency/threads.md +++ b/src/concurrency/threads.md @@ -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`. - -
- -- 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` - -- 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 - -
+{{%segment outline}} diff --git a/src/concurrency/threads/plain.md b/src/concurrency/threads/plain.md new file mode 100644 index 00000000..286e0bc3 --- /dev/null +++ b/src/concurrency/threads/plain.md @@ -0,0 +1,78 @@ +--- +minutes: 15 +--- + +# Plain 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`. + +
+ +- 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` + +- 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 + +
diff --git a/src/concurrency/scoped-threads.md b/src/concurrency/threads/scoped.md similarity index 97% rename from src/concurrency/scoped-threads.md rename to src/concurrency/threads/scoped.md index 911cb3f2..89d782bb 100644 --- a/src/concurrency/scoped-threads.md +++ b/src/concurrency/threads/scoped.md @@ -1,3 +1,7 @@ +--- +minutes: 13 +--- + # Scoped Threads Normal threads cannot borrow from their environment: diff --git a/src/async.md b/src/concurrency/welcome-async.md similarity index 94% rename from src/async.md rename to src/concurrency/welcome-async.md index a0315370..99ac6ada 100644 --- a/src/async.md +++ b/src/concurrency/welcome-async.md @@ -1,8 +1,9 @@ --- session: Afternoon +target_minutes: 180 --- -# Async Rust +# Welcome "Async" is a concurrency model where multiple tasks are executed concurrently by executing each task until it would block, then switching to another task that is @@ -27,3 +28,7 @@ available. - JavaScript's `Promise` is similar, but again callback-based. The language runtime implements the event loop, so many of the details of Promise resolution are hidden. + +## Schedule + +{{%session outline}} diff --git a/src/concurrency.md b/src/concurrency/welcome.md similarity index 93% rename from src/concurrency.md rename to src/concurrency/welcome.md index 18f8f1f8..0a35006d 100644 --- a/src/concurrency.md +++ b/src/concurrency/welcome.md @@ -1,6 +1,7 @@ --- course: Concurrency session: Morning +target_minutes: 180 --- # Welcome to Concurrency in Rust @@ -12,6 +13,10 @@ 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. +## Schedule + +{{%session outline}} +
- Rust lets us access OS concurrency toolkit: threads, sync. primitives, etc. diff --git a/src/exercises/concurrency/afternoon.md b/src/exercises/concurrency/afternoon.md deleted file mode 100644 index 00a0fd18..00000000 --- a/src/exercises/concurrency/afternoon.md +++ /dev/null @@ -1,17 +0,0 @@ -# Exercises - -To practice your Async Rust skills, we have again two exercises for you: - -- Dining philosophers: we already saw this problem in the morning. This time you - are going to implement it with Async Rust. - -- A Broadcast Chat Application: this is a larger project that allows you - experiment with more advanced Async Rust features. - -
- -After looking at the exercises, you can look at the [solutions] provided. - -[solutions]: solutions-afternoon.md - -
diff --git a/src/running-the-course/course-structure.md b/src/running-the-course/course-structure.md index 6ca63d64..bf0334fe 100644 --- a/src/running-the-course/course-structure.md +++ b/src/running-the-course/course-structure.md @@ -70,6 +70,8 @@ cargo add tokio --features full cargo run ``` +{{%course outline Concurrency}} + ## Format The course is meant to be very interactive and we recommend letting the