Skip to content

Commit c60070b

Browse files
authored
Small fixes to concurrency material (#2737)
See individual commits.
1 parent fc6e5c7 commit c60070b

File tree

3 files changed

+39
-25
lines changed

3 files changed

+39
-25
lines changed

src/concurrency/shared-state/arc.md

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,40 @@ minutes: 5
44

55
# `Arc`
66

7-
[`Arc<T>`][1] allows shared read-only access via `Arc::clone`:
7+
[`Arc<T>`][1] allows shared, read-only ownership via `Arc::clone`:
88

99
```rust,editable
1010
use std::sync::Arc;
1111
use std::thread;
1212
13+
/// A struct that prints which thread drops it.
14+
#[derive(Debug)]
15+
struct WhereDropped(Vec<i32>);
16+
17+
impl Drop for WhereDropped {
18+
fn drop(&mut self) {
19+
println!("Dropped by {:?}", thread::current().id())
20+
}
21+
}
22+
1323
fn main() {
14-
let v = Arc::new(vec![10, 20, 30]);
24+
let v = Arc::new(WhereDropped(vec![10, 20, 30]));
1525
let mut handles = Vec::new();
16-
for _ in 0..5 {
26+
for i in 0..5 {
1727
let v = Arc::clone(&v);
1828
handles.push(thread::spawn(move || {
29+
// Sleep for 0-500ms.
30+
std::thread::sleep(std::time::Duration::from_millis(500 - i * 100));
1931
let thread_id = thread::current().id();
2032
println!("{thread_id:?}: {v:?}");
2133
}));
2234
}
2335
36+
// Now only the spawned threads will hold clones of `v`.
37+
drop(v);
38+
39+
// When the last spawned thread finishes, it will drop `v`'s contents.
2440
handles.into_iter().for_each(|h| h.join().unwrap());
25-
println!("v: {v:?}");
2641
}
2742
```
2843

src/concurrency/shared-state/example.md

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ use std::thread;
1212
1313
fn main() {
1414
let v = vec![10, 20, 30];
15-
let handle = thread::spawn(|| {
16-
v.push(10);
17-
});
18-
v.push(1000);
15+
let mut handles = Vec::new();
16+
for i in 0..5 {
17+
handles.push(thread::spawn(|| {
18+
v.push(10 * i);
19+
println!("v: {v:?}");
20+
}));
21+
}
1922
20-
handle.join().unwrap();
21-
println!("v: {v:?}");
23+
handles.into_iter().for_each(|h| h.join().unwrap());
2224
}
2325
```
2426

@@ -32,21 +34,17 @@ use std::thread;
3234
3335
fn main() {
3436
let v = Arc::new(Mutex::new(vec![10, 20, 30]));
35-
36-
let v2 = Arc::clone(&v);
37-
let handle = thread::spawn(move || {
38-
let mut v2 = v2.lock().unwrap();
39-
v2.push(10);
40-
});
41-
42-
{
43-
let mut v = v.lock().unwrap();
44-
v.push(1000);
37+
let mut handles = Vec::new();
38+
for i in 0..5 {
39+
let v = Arc::clone(&v);
40+
handles.push(thread::spawn(move || {
41+
let mut v = v.lock().unwrap();
42+
v.push(10 * i);
43+
println!("v: {v:?}");
44+
}));
4545
}
4646
47-
handle.join().unwrap();
48-
49-
println!("v: {v:?}");
47+
handles.into_iter().for_each(|h| h.join().unwrap());
5048
}
5149
```
5250

@@ -56,7 +54,7 @@ Notable parts:
5654
orthogonal.
5755
- Wrapping a `Mutex` in an `Arc` is a common pattern to share mutable state
5856
between threads.
59-
- `v: Arc<_>` needs to be cloned as `v2` before it can be moved into another
57+
- `v: Arc<_>` needs to be cloned to make a new reference for each new spawned
6058
thread. Note `move` was added to the lambda signature.
6159
- Blocks are introduced to narrow the scope of the `LockGuard` as much as
6260
possible.

src/concurrency/sync-exercises/link-checker.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,12 @@ fn spawn_crawler_threads(
105105
result_sender: mpsc::Sender<CrawlResult>,
106106
thread_count: u32,
107107
) {
108+
// To multiplex the non-cloneable Receiver, wrap it in Arc<Mutex<_>>.
108109
let command_receiver = Arc::new(Mutex::new(command_receiver));
109110

110111
for _ in 0..thread_count {
111112
let result_sender = result_sender.clone();
112-
let command_receiver = command_receiver.clone();
113+
let command_receiver = Arc::clone(&command_receiver);
113114
thread::spawn(move || {
114115
let client = Client::new();
115116
loop {

0 commit comments

Comments
 (0)