rust并发编程的几个概念 | 1.线程 1.线程是操作系统调度的基本单位,可独立执行任务 2. rust提供了 std::thread 模块,用于创建和管理线程 2.所有权和借用 1.rust通过所有权和借用机制来确保内存安全 2.在并发环境下,所有权和借用规则有助于防止数据竞争等问题 3.原子操作 1.原子操作可以在多线程下安全更新共享数据 2.使用 std::sync::atomic 实现原子操作 4.通道 1.通道提供一种在多线程间传递消息的机制,有助于实现无锁编程 2.rust提供了 std::sync::mpsc模块,用于实现线程间的通信 mpsc:Multiple Producer ,Single Consumter 多个生产者线程发送消息到一个 通道,单个消费者线程接受该通道信息 5.Arc(Atomic Refrence Counting) 1.Arc可以在多个线程间共享数据 同时提供引用计数来管理生命周期 2.rust提供了 std::sync::Arc 用于实现多线程环境下智能指针 解释 1.什么是自动引用计数 每创建一个对象,系统会该对象分配一个计数器,每当有一个新的引用指向该对象时,计数器就会增加 当引用不再存在时,计数器就会减少 |
rust并发编程示例_创建线程 | use std::thread; use std::time::Duration; fn main() { println!("Hello from the main thread!"); // 创建一个新的线程 let handle = thread::spawn(|| { //spawn:生成,创建。它接受一个必包作为参数,定义了新线程将要执行的代码 // || : 作为必包的参数分隔符 ||表示该必包不接受任何参数 for i in 1..10 { println!("Hello from the spawned thread! {}", i); thread::sleep(Duration::from_millis(1)); } }); // 等待新线程结束 handle.join().unwrap(); //unwarp:解包,展开 println!("Back to the main thread!"); } |
rust并发编程示例_使用通道传递消息 | use std::sync::mpsc; use std::thread; fn main() { // 创建一个通道 let (tx, rx) = mpsc::channel(); // 创建一个线程来发送消息 let tx1 = tx.clone(); thread::spawn(move || { //move:当一个必包通过move关键字捕获变量时,它将取得这些变量的所有权 let vals = vec![ //vec! 创建向量 String::from("hello"), String::from("world"), ]; for val in vals { tx1.send(val).unwrap(); thread::sleep(std::time::Duration::from_secs(1)); } }); thread::spawn(move || { let vals = vec![ String::from("foo"), String::from("bar"), ]; for val in vals { tx.send(val).unwrap(); thread::sleep(std::time::Duration::from_secs(1)); } }); // 接收消息 for received in rx { println!("Got: {}", received); } } |
rust并发编程示例_使用Arc实现共享数据 | use std::sync::{Arc, Mutex}; use std::thread; fn main() { let counter = Arc::new(Mutex::new(0)); //创建共享计数器 用 Arc 来允许这个互斥锁的所有权在多个线程之间共享 //1.Mutext::new(0) :创建一个互斥锁,它内部包含了一个初始值为0的整数 //比喻:你有一个数字(初始值是 0),并且你把它放在一个保险箱(互斥锁)里,这样只有拥有钥匙(锁)的人才能打开它并修改里面的数字。 //2.Arc::new:增加引用计数,每个线程都有自己的数据引用 //比喻:然后,你制作了这个保险箱的多个副本(使用 Arc),每个副本都可以被一个线程安全地使用,而原始的数字始终保持一致和安全。 let mut handles = Vec::new(); //存储每个新创建的线程的句柄 //1.Vec::new() 创建了一个空的动态数组。动态数组可以存储一系列的元素,并且可以根据需要自动增长或缩小。 //比喻:创建了一个名为 handles 的新盒子(变量),并且这个盒子是可变的,意味着你可以往里面放东西或者把里面的东西拿出来。 //这个盒子(handles)目前是空的,但它是专门用来存放“句柄”的。 for _ in 0..10 { let counter_clone = Arc::clone(&counter); // Arc::clone 方法来增加 Arc 的引用计数,这样每个线程都可以拥有 counter 的一个引用 let handle = thread::spawn(move || { let mut num = counter_clone.lock().unwrap(); 使用 lock 方法来获取互斥锁,这会阻塞当前线程直到锁可用 *num += 1; //一旦获取了互斥锁,就增加包装在互斥锁内部的计数器的值 }); handles.push(handle); //将新线程的句柄添加到 handles 向量中。 } for handle in handles { handle.join().unwrap(); //使用 join 方法等待每个线程完成 } println!("Final count: {}", *counter.lock().unwrap()); //再次获取互斥锁,打印出最终的计数器值 //unwrap():这个方法用于处理 Result 类型。在这个上下文中,lock() 方法返回的是一个 Result 类型,它可以是 Ok,表示成功获取了锁,或者 Err,表示在尝试获取锁时发生了错误。unwrap() 方法会检查 Result,如果是 Ok,它会返回里面的值(在这个例子中是锁住的计数器),如果是 Err,程序将会 panic(即异常终止) } |
Arc上述代码解释(比喻) | 想象一下,你有一个特殊的计数器(就像一个可以计数的魔法盒子),这个计数器放在一个保险箱里,这样只有拥有钥匙的人才能打开它并改变里面的数字。现在,你想让10个朋友在不同的房间里同时增加这个计数器的值,而且每个人只能增加一次。 准备一个空列表来存放朋友的遥控器(线程句柄): 创建10个朋友(线程)来增加计数器的值: 在新线程中,朋友会先打开保险箱(counter_clone.lock().unwrap()),然后增加计数器的值(*num += 1;),最后保险箱会自动上锁。 等待所有朋友完成增加计数器的任务: 打印最终的计数器值: 总的来说,这段代码展示了如何在 Rust 中使用多线程安全地增加一个共享计数器的值。 |
rust学习_并发编程
于 2024-09-17 10:49:30 首次发布