文章目录
一、简介
二、创建线程
1.创建一个线程
use std::thread;
fn main() {
// 创建一个新线程
let handle = thread::spawn(|| {
// 在新线程中执行的代码
println!("Hello from a new thread!");
});
// 等待线程结束
handle.join().unwrap();
}
2.创建多个线程
use std::thread;
fn main() {
// 创建一个向量来存储线程的句柄
let mut threads = vec![];
// 创建多个线程
for i in 0..5 {
// 使用闭包捕获变量i的值
let thread_number = i;
let handle = thread::spawn(move || {
// 在新线程中打印线程编号
println!("线程 {} 正在运行", thread_number);
});
// 将线程句柄添加到向量中
threads.push(handle);
}
// 等待所有线程完成
for handle in threads {
handle.join().unwrap();
}
// 在主线程中打印一些信息
for i in 0..5 {
println!("主线程打印数字: {}", i);
}
}
# 输出结果:
线程 0 正在运行
线程 1 正在运行
线程 2 正在运行
线程 3 正在运行
线程 4 正在运行
主线程打印数字: 0
主线程打印数字: 1
主线程打印数字: 2
主线程打印数字: 3
主线程打印数字: 4
- 从输出结果上看,仍然像是顺序执行,所以这里引入一个休眠,让线程执行的时候随机休眠0-3秒。
生成随机数
# 首先需要在Cargo.toml中添加以下内容
[dependencies]
rand = "0.8"
# 然后在代码中用use 引入
use rand::Rng;
use rand::thread_rng;
fn main() {
let mut rng = thread_rng();
for _i in 0..10{
let random_number = rng.gen_range(1..4);
println!("随机数是: {}", random_number);
}
}
# 结果:
随机数是: 3
随机数是: 1
随机数是: 3
随机数是: 1
随机数是: 3
随机数是: 1
随机数是: 3
随机数是: 2
随机数是: 3
随机数是: 1
随机数生成的区间与循环一样,是一个前闭后开的区间
尝试让程序睡一会儿
use rand::Rng;
use std::{thread::sleep, time::Duration};
fn main() {
// 创建一个随机数生成器
let mut rng = rand::thread_rng();
// 生成一个0到3之间的随机秒数
let random_seconds: u64 = rng.gen_range(0..4);
// 将秒数转换为Duration
let duration = Duration::from_secs(random_seconds);
// 让当前线程睡眠指定的时间
sleep(duration);
// 之后的代码会在等待后执行
println!("等待了 {} 秒", random_seconds);
}
引入多线程
use rand::Rng;
use std::{thread::sleep, time::Duration};
use std::thread;
fn main() {
// 创建一个向量来存储线程的句柄
let mut threads = vec![];
// 创建多个线程
for i in 1..=10 {
// 使用闭包捕获变量i的值
let thread_number = i;
let handle = thread::spawn(move || {
// 在新线程中打印线程编号
println!("线程 {} 正在运行", thread_number);
// 创建一个随机数生成器
let mut rng = rand::thread_rng();
// 生成一个0到3之间的随机秒数
let random_seconds: u64 = rng.gen_range(0..4);
// 将秒数转换为Duration
let duration = Duration::from_secs(random_seconds);
// 让当前线程睡眠指定的时间
sleep(duration);
println!("线程 {} 运行结束,休息了{}秒.", thread_number,random_seconds);
});
// 将线程句柄添加到向量中
threads.push(handle);
}
// 等待所有线程完成
for handle in threads {
handle.join().unwrap();
}
// 在主线程中打印一些信息
for i in 0..5 {
println!("主线程打印数字: {}", i);
}
}
# 输出结果
线程 3 正在运行
线程 2 正在运行
线程 5 正在运行
线程 7 正在运行
线程 7 运行结束,休息了0秒.
线程 4 正在运行
线程 6 正在运行
线程 1 正在运行
线程 8 正在运行
线程 9 正在运行
线程 10 正在运行
线程 6 运行结束,休息了1秒.
线程 4 运行结束,休息了1秒.
线程 3 运行结束,休息了1秒.
线程 9 运行结束,休息了1秒.
线程 1 运行结束,休息了2秒.
线程 10 运行结束,休息了2秒.
线程 5 运行结束,休息了2秒.
线程 2 运行结束,休息了3秒.
线程 8 运行结束,休息了3秒.
主线程打印数字: 0
主线程打印数字: 1
主线程打印数字: 2
主线程打印数字: 3
主线程打印数字: 4
三、线程返回值的处理
1.每个线程处理一个独立的值
use std::thread;
fn main() {
let mut handles = vec![];
for i in 0..5 {
let handle = thread::spawn(move || {
return i*i;
});
handles.push(handle);
}
let mut results = vec![];
for handle in handles {
match handle.join() {
Ok(value) => results.push(value),
Err(e) => println!("Thread panicked: {:?}", e),
}
}
println!("Results: {:?}", results); //Results: [0, 1, 4, 9, 16]
}
2.多个线程处理一个值
Arc(原子引用计数)
use std::sync::Arc;
use std::thread;
fn main() {
// 创建一个要在多个线程之间共享的值
let data = Arc::new(vec![1, 2, 3, 4, 5]);
// 创建一个向量来存储线程的句柄
let mut handles = vec![];
println!("Thread {:?} is reading value: {:?}", thread::current().id(), &data); // 主线程的线程ID为 1
// 创建几个线程来只读访问数据
for _i in 0..data.len() {
let data = data.clone(); // 克隆Arc以便在线程中使用
let handle = thread::spawn(move || {
// 获取Vec的引用以便索引
// 使用 {:?} 来打印 ThreadId
println!("Thread {:?} is reading value: {:?}", thread::current().id(), &data);
});
handles.push(handle);
}
// 等待所有线程完成
for handle in handles {
handle.join().unwrap();
}
}
# 运行结果
Thread ThreadId(1) is reading value: [1, 2, 3, 4, 5]
Thread ThreadId(2) is reading value: [1, 2, 3, 4, 5]
Thread ThreadId(3) is reading value: [1, 2, 3, 4, 5]
Thread ThreadId(4) is reading value: [1, 2, 3, 4, 5]
Thread ThreadId(5) is reading value: [1, 2, 3, 4, 5]
Thread ThreadId(6) is reading value: [1, 2, 3, 4, 5]
Mutex(互斥锁)
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
// 创建一个Arc包裹的互斥锁和值
let counter = Arc::new(Mutex::new(1));
let mut handles = vec![];
// 创建几个线程来增加计数器
for i in 1..10 {
// 克隆Arc智能指针,而不是Mutex或它的值
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
// 获取互斥锁以便修改值
let mut num = counter.lock().unwrap();
*num *=i;
});
handles.push(handle);
}
// 等待所有线程完成
for handle in handles {
handle.join().unwrap();
}
// 输出最终计数器的值
println!("Result: {}", *counter.lock().unwrap()); // Result: 362880
}
RwLock(读写锁)
use std::sync::{Arc, RwLock};
fn main() {
let data = Arc::new(RwLock::new(0));
let mut handles = vec![];
// 创建多个读线程
for i in 0..5 {
let data = Arc::clone(&data);
let handle = std::thread::spawn(move || {
let num = data.read().unwrap();
println!("Thread {} Reading value: {}", i,*num);
});
handles.push(handle);
}
// 创建一个写线程
let data = Arc::clone(&data);
let handle = std::thread::spawn(move || {
let mut num = data.write().unwrap();
*num += 1;
println!("Writing value: {}", *num);
});
handles.push(handle);
for handle in handles {
handle.join().unwrap();
}
}
# 第一次执行结果
Thread 0 Reading value: 0
Thread 3 Reading value: 0
Thread 1 Reading value: 0
Thread 4 Reading value: 0
Thread 2 Reading value: 0
Writing value: 1
# 第二次执行结果
Thread 0 Reading value: 0
Thread 3 Reading value: 0
Thread 1 Reading value: 0
Thread 4 Reading value: 0
Thread 2 Reading value: 0
Writing value: 1
这里有一个问题,就是如果写线程最后执行,那么读线程读的都是原始数据,如果写线程先执行,那么读的就是修改后的数据,所以对读写顺序有要求的话应该做好时序的控制