1. 线程基础
创建线程:
use std::thread;
use std::time::Duration;
fn test1() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("{}", i);
thread::sleep(Duration::from_millis(1));
}
});
handle.join().unwrap(); // 等待线程结束
}
使用move关键字:
fn test02() {
let v = vec![1,2,3];
// move 强制闭包获取外部变量所有权
let handle = thread::spawn(move || {
for i in v.iter() {
println!("{}", i);
}
});
handle.join().unwrap();
}
关键点:
- thread::spawn 创建新线程
- join() 等待线程完成
- move 关键字将外部变量所有权转移到闭包中
2. 消息传递并发
通道基础:
use std::sync::mpsc; // multiple producer, single consumer
fn test3() {
let (tx, rx) = mpsc::channel();
let handle = thread::spawn(move || {
let value = String::from("hello");
thread::sleep(Duration::from_millis(10000));
match tx.send(value) {
Result::Ok(_) => println!("done"),
Result::Err(e) => println!("error {}", e),
}
});
let received = match rx.try_recv() {
Result::Ok(val) => val,
Result::Err(e) => panic!("NO EXISTING MESSAGE! ERROR: {}", e),
};
println!("Got: {}", received);
}
所有权转移:
fn test4() {
let (tx, rx) = mpsc::channel();
let handle = thread::spawn(move || {
let value = String::from("hello");
tx.send(value).unwrap();
// 发送后不能再使用 value,所有权已转移!
// println!("sent: {}", value); // 这行会编译错误
});
let received = rx.recv().unwrap();
println!("Got: {}", received);
}
多个值发送:
fn test5() {
let (tx, rx) = mpsc::channel();
let handle = thread::spawn(move || {
let values = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("thread"),
];
for value in values.into_iter() {
tx.send(value).unwrap();
thread::sleep(Duration::from_millis(2000));
}
});
for value in rx.iter() {
println!("Got: {}", value);
}
}
消息传递特点:
- mpsc::channel() 创建发送端和接收端
- send() 转移值的所有权
- recv() 阻塞等待,try_recv() 非阻塞
- 通道自动在发送/接收端被丢弃时关闭
3. 共享状态并发
互斥锁基础:
fn test6() {
let data = Mutex::new(5);
{
// 获取锁,阻塞直到获得锁
let mut m = data.lock().unwrap();
*m += 10;
} // 离开作用域自动释放锁
println!("data: {:?}", data);
}
多线程共享Mutex:
fn test7() {
let data = Arc::new(Mutex::new(5));
let mut v = vec![];
for _ in 0..5 {
let data = Arc::clone(&data);
let handle = thread::spawn(move || {
let mut number = data.lock().unwrap();
*number += 10;
});
v.push(handle);
}
for handle in v {
handle.join().unwrap();
}
println!("{:?}", data);
}
共享状态关键点:
- Mutex<t> 提供内部可变性
- 访问数据之前必须调用 lock() 获取锁
- Arc<t> 是线程安全的引用计数指针
- Rc<t> 不能在多线程中使用
4. 死锁
尝试自己编写一个死锁的案例:
fn dead_lock() {
let data1 = Arc::new(Mutex::new(5));
let data2 = Arc::new(Mutex::new(10));
let data11 = Arc::clone(&data1);
let data22 = Arc::clone(&data2);
// 线程1:先锁 data1,再锁 data2
let handle1 = thread::spawn(move || {
let mut number1 = data11.lock().unwrap();
thread::sleep(Duration::from_millis(500));
let mut number2 = data22.lock().unwrap(); // 可能阻塞在这里
println!("number1: {:?}", number1);
println!("number2: {:?}", number2);
});
let data111 = Arc::clone(&data1);
let data222 = Arc::clone(&data2);
// 线程2:先锁 data2,再锁 data1
let handle2 = thread::spawn(move || {
let mut number2 = data222.lock().unwrap();
thread::sleep(Duration::from_millis(500));
let mut number1 = data111.lock().unwrap(); // 可能阻塞在这里
println!("number1: {:?}", number1);
println!("number2: {:?}", number2);
});
handle1.join().unwrap();
handle2.join().unwrap();
}