thread::spawn和thread::scope
1. move 所有权
flowchart LR
%% ① move 所有权转移
subgraph Move["① move 所有权转移(不共享)"]
M_Main[主线程]
M_a[变量 a]
M_Child[子线程]
M_aa[变量 a]
%% 数据流
M_Main --> M_a
M_a -->|"move a"| M_Child
M_Child -->|"独占修改 ✅"| M_aa --> M_Child
M_a -.-> |"主线程 变量a 失效"| M_aa
%% 样式
style M_Main fill:#ffe6e6,stroke:#ff4d4d
style M_Child fill:#fff2cc,stroke:#ff9900
style M_a fill:#ffcccc,stroke:#ff0000
end
use std::thread;
fn main() {
let a = String::from("hello");
thread::spawn(move || {
println!("{}", a); // 独占使用
}).join().unwrap();
// println!("{}", a); // ❌ 已被 move
}
2. Arc<Mutex>
flowchart LR
%% ② Arc<Mutex>(共享 + 并发安全)
subgraph ArcMutex["② Arc< Mutex>(共享 + 并发安全)"]
A_Main[主线程]
A_Child1[子线程1]
A_Child2[子线程2]
A_Data["Arc< Mutex< T>>(共享数据)"]
A_Main -->|"Arc::clone(&a)"| A_Child1
A_Main -->|"Arc::clone(&a)"| A_Child2
A_Child1 -->|"lock() 修改 ✅"| A_Data
A_Child2 -->|"lock() 修改 ✅"| A_Data
style A_Main fill:#e6ffe6,stroke:#00cc44
style A_Child1 fill:#cce6ff,stroke:#0066ff
style A_Child2 fill:#cce6ff,stroke:#0066ff
style A_Data fill:#ccffcc,stroke:#00aa00
end
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let data = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..2 {
let d = Arc::clone(&data);
handles.push(thread::spawn(move || {
// d.lock() 返回的是一个 MutexGuard,这是一个 RAII 类型的智能指针。
let mut num = d.lock().unwrap();
*num += 1;
// 当 num 离开作用域时,MutexGuard 会被 drop,锁被释放。
}));
}
for h in handles { h.join().unwrap(); }
// 打印时你要访问 data 的内容,此时需要一个新的锁来保证线程安全。
// 因为 Arc<Mutex<T>> 的内部数据是被 Mutex 保护的,所以每次访问都必须拿锁。
println!("result = {}", *data.lock().unwrap()); // result = 2
}
3. thread::scope
flowchart LR
%% ③ thread::scope(借用局部变量)
subgraph Scope["③ thread::scope(借用局部变量)"]
S_Main[主线程(作用域)]
S_a[变量 a(局部变量)不可变]
%% 子线程大框
subgraph Threads["子线程(作用域内)"]
S_Child1[子线程1]
S_Child2[子线程2]
S_a1[不可变借用 变量 a(局部变量)]
S_a2[不可变借用 变量 a(局部变量)]
end
%% 数据流
S_Main --> S_a
S_a -->|"&a"| S_Child1
S_a -->|"&a"| S_Child2
S_Child1 -->|"&a 只读 ✅"| S_a1 --> S_Child1
S_Child2 -->|"&a 只读 ✅"| S_a2 --> S_Child2
%% 作用域结束自动 join
S_Child1 -.->|"作用域结束自动 join"| S_Main
S_Child2 -.->|"作用域结束自动 join"| S_Main
%% 样式
style S_Main fill:#f0ccff,stroke:#9900ff
style S_a fill:#e6ccff,stroke:#9900ff
style S_Child1 fill:#f9e6ff,stroke:#9900ff
style S_Child2 fill:#f9e6ff,stroke:#9900ff
style Threads fill:#f2e6ff,stroke:#9900ff,stroke-width:2px
end
use std::thread;
fn main() {
let a = String::from("hello");
thread::scope(|s| {
s.spawn(|| println!("thread1: {}", a));
s.spawn(|| println!("thread2: {}", a));
});
println!("{}", a); // ✅ 作用域结束后还能用
}
单线程可变借用
-
只有一个线程拿到
&mut a。 -
作用域结束前没有其他线程访问
a。
thread::scope(|s| {
s.spawn(|| {
let a_mut = &mut a; // 独占可变借用
a_mut.push_str(" world");
});
});
多线程可变借用
- Rust 不允许同时把同一个
&mut a借给多个线程
thread::scope(|s| {
s.spawn(|| { &mut a }); // ❌
s.spawn(|| { &mut a }); // ❌
});
多线程安全可变共享
- 如果多个线程都要修改同一个变量,就必须用 同步原语:
Mutex<T>(互斥锁)RwLock<T>(读写锁)
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let data = Arc::new(Mutex::new(0));
thread::scope(|s| {
for _ in 0..2 {
let d = Arc::clone(&data);
s.spawn(move || {
let mut num = d.lock().unwrap();
*num += 1;
});
}
});
println!("result = {}", *data.lock().unwrap());
}

浙公网安备 33010602011771号