Rust多线程下共享变量
阅读须知
阅读本文,你可以知道:
- 使用Arc,在多线程访问共享不可变变量
- Arc与Mutex、Arc与Atomic,在多线程访问共享可变变量
但是,本文不涉及原理性介绍,请自行搜索。
Arc
线程安全的引用计数器,Arc
代表Atomaticlly Reference Counted
/ 原子引用计数。
该类型Arc
提供T在堆中分配的type值的共享所有权。调用clone将Arc产生一个新Arc实例,该实例指向堆上与源相同的分配Arc,同时增加引用计数。当Arc 指向给定分配的最后一个指针被破坏时,存储在该分配中的值(通常称为“内部值”)也会被删除。
默认情况下,Rust中的共享引用不允许更改,Arc
也不例外:您通常无法获得对内某些内容的可变引用Arc。如果通过需要发生变异Arc,使用Mutex
,RwLock
或者一个Atomic
类型。
多线程访问共享不可变变量
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
#[test]
pub fn test_immutable() {
let b = Arc::new(1);
let b1 = b.clone();
let b2 = b.clone();
let t1 = thread::spawn(move || {
println!("b1,addr:{:p},values:{}", b1.as_ref(), b1);
});
let t2 = thread::spawn(move || {
println!("b2,addr:{:p},values:{}", b2.as_ref(), b2);
});
println!("b,addr:{:p},values:{}", b.as_ref(), b);
t2.join();
t1.join();
}
Mutex
互斥器
(mutex) 是mutual exlusion的缩写,也就是说,任意时刻,其只允许一个线程访问某些数据。为了访问互斥器中的数据,线程首先需要获得互斥器的锁
,来表明其希望访问数据。
Arc+Mutex实现多线程下多所有权
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
#[test]
pub fn test_mutable() {
let b = Arc::new(Mutex::new(1));
let mut handles = vec![];
// 10个线程对b加1
for i in 10..20 {
let b1 = Arc::clone(&b);
let handle = thread::Builder::new().name(format!("thread-{}", i)).spawn(move || {
// lock 调用返回MutexGuard的智能指针,它实现了Deref来指向其内部数据,其也提供了一个Drop实现,当它离开作用域时自动释放锁
let mut guard = b1.lock().unwrap();
*guard = *guard + 1;
println!("{},addr:{:p},value{}", thread::current().name().unwrap(),b1.as_ref() ,*guard);
// guard 离开作用域后会自动释放锁
}).unwrap();
handles.push(handle);
}
// 10个线程对b减1
for i in 0..10 {
let b2 = Arc::clone(&b);
let handle = thread::Builder::new().name(format!("thread-{}", i)).spawn(move || {
let mut guard = b2.lock().unwrap();
*guard = *guard - 1;
println!("{},addr:{:p},value{}", thread::current().name().unwrap(),b2.as_ref() ,*guard);
}).unwrap();
handles.push(handle);
}
// for handle in handles{
// handle.join().unwrap();
// }
thread::sleep(Duration::from_secs(1));
println!("b,addr:{:p},values:{}", b.as_ref(), b.lock().unwrap());
}
AtomicUsize
Arc+AtomicUsize 实现多线程下多所有权
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
#[test]
fn test_mutable() {
let arc = Arc::new(AtomicUsize::new(1));
let mut handles = vec![];
for _ in 0..10 {
let val = Arc::clone(&arc);
let handle = thread::spawn(move || {
let v = val.fetch_add(1, Ordering::SeqCst);
println!("{:?},{:p}", v, Arc::::as_ptr(&val));
});
handles.push(handle);
}
for _ in 0..10 {
let val = Arc::clone(&arc);
let handle = thread::spawn(move || {
let v = val.fetch_sub(1, Ordering::SeqCst);
println!("{:?},{:p}", v, Arc::::as_ptr(&val));
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("final,{:?},{:p}", arc, Arc::::as_ptr(&arc));
}
参考链接
https://kaisery.github.io/trpl-zh-cn/ch16-00-concurrency.html