十、标准库 - 并发
Published on
安全并高效地处理并发是Rust的主要目标之一。Rust使用所有权与类型系统可以同时处理内存安全与并发安全问题。
线程(Thread)
// 使用spawn建立线程,使其运行一个闭包
let handle = thread::spawn(|| {
for i in 1..10 {
println!("hi number {} from the spawned thread!", i);
}
});
// 使用join等待线程结束
handle.join().unwrap();
// 使用sleep令当前线程休眠
thread::sleep(Duration::from_millis(1));
// 为了使线程闭包能够使用外部变量,需要使用move关键字移动所有权
let v = vec![1, 2, 3];
let handle = thread::spawn(move || {
println!("Here's a vector: {:?}", v);
});
通道
通过消息传递来进行安全的并发是一种越来越流行的思想。因此Rust标准库中实现了通道,它可以由sender发送数据给receiver。
// 建立通道,获得sender与receiver
let (tx, rx) = mpsc::channel();
// 在新线程中使用sender发送数据,注意需要将sender移动至新线程
thread::spawn(move || {
let val = String::from("Hi");
// 为了保证安全,使用通道发送数据时,数据被移动
tx.send(val).unwrap();
});
// 在主线程中使用receiver接收数据
let received = rx.recv().unwrap();
println!("Got: {}", received);
通道可以有多个sender,但只能有一个receiver
let (tx, rx) = mpsc::channel();
// 通过复制可以有多个sender
let tx1 = tx.clone();
thread::spawn(move || {
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("thread"),
];
for val in vals {
tx1.send(val).unwrap();
thread::sleep(Duration::from_secs(1));
}
});
// 通过复制可以有多个sender
thread::spawn(move || {
let vals = vec![
String::from("more"),
String::from("messages"),
String::from("for"),
String::from("you"),
];
for val in vals {
tx.send(val).unwrap();
thread::sleep(Duration::from_secs(1));
}
});
// 只能有一个receiver,可以使用for语句迭代
for received in rx {
println!("Got: {}", received);
}
互斥锁(Mutex)
使用通道时,不同线程并不共享数据,另外一种并发方式是多个线程共享数据。但是为了保证同一时间只能有一个线程可以访问数据,需要使用互斥锁。
// 声明一个互斥锁Mutex,为了可以由多个线程共享,需要声明为线程安全智能指针Arc
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
// 启动10个线程
for _ in 0..10 {
// 复制Mutex指针
let counter = Arc::clone(&counter);
// 需要使用move移动指针所有权
let handle = thread::spawn(move || {
// 使用数据前需要使用lock加锁
let mut num = counter.lock().unwrap();
// 之后可以使用数据
*num += 1;
// 函数退出后自动解锁
});
handles.push(handle);
}
// 等待所有线程结束
for handle in handles {
handle.join().unwrap();
}
Sync与Send特性
Rust语言内置了Sync与Send两个标记特性用于处理并发。它们用于标记,因此没有方法需要实现。但是要实现它们的功能需要使用unsafe代码。
- Send:实现此特性的类型,其值的所有权可以在线程间转移
- Sync:实现此特性的类型,其值可以由多个线程引用