每天进步一点点。
rust中用多个线程对同一个整数进行加数操作。为了保证线程安全,需要通过Mutex类型变量的lock方法进行加锁。
我们知道,Mutex类型变量也要遵循rust的所有权机制,如果想要在线程间共享Mutex的引用,需要通过Arc::new方法创建一个Mutex变量的原子引用计数器,然后再克隆多个Arc,通过闭包move到线程中。
相关源码如下:
use std::sync::{Arc, Mutex};
use std::thread;
use std::thread::Builder;
fn main() {
// 在堆上分配一个i32整数0,通过智能指针Box将其绑定到number变量上
// 注意这儿无论是let number还是let mut number都可以,因为Mutex::new内部使用了UnsafeCell
let number = Box::new(0);
// 创建一个原子引用计数器counter
let counter = Arc::new(Mutex::new(number));
// 声明一个可变数组,里面存放线程的JoinHandle
let mut thread_handles = vec![];
// 从0到9
for i in 0..10 {
// 线程builder,设置了线程的名字是thread-i这种形式
let builder = Builder::new().name(format!("thread-{}", i));
// 每个线程都有一个对counter的引用
let thread_counter = Arc::clone(&counter);
// 创建并运行线程,通过move将thread_counter的所有权转移到闭包中
let handle = builder.spawn(move || {
println!("thread:{} begin to add 1..=100", thread::current().name().unwrap());
// 对每一个子线程,从1加到100,即5050
for j in 1..=100 {
// 加锁,并获取被保护的对象
let mut num = thread_counter.lock().unwrap();
// 执行加数字操作
*(*num) += j;
println!("{} add {} to number", thread::current().name().unwrap(), j);
// 代码块结束后,会释放掉锁
}
}).unwrap();
// 将线程的handle放到数组中,方便后续主线程对所有子线程进行join操作
thread_handles.push(handle);
}
for handle in thread_handles {
// 等待每一个子线程都完成
handle.join().unwrap();
}
// 输出最后的结果
println!("final result:{:#?}", counter.to_owned());
// 下面这行会编译报错,因为number已经被move到Mutex中了,受Mutex保护,一切对number的操作都要通过Mutex的保护,所以不能再直接访问number
// println!("final result:{:#?}", number);
}
程序运行的结果如下:
因为1+2+3+…+100=5050,10个线程分别加上5050就是50500,所以程序正确地使用了多个线程对整数进行加数操作。