rust是一种强类型、高性能的系统编程语言,其官方文档中强调了rust的标准库具有良好的并发编程支持。thread是rust中的一种并发编程方式,本文将介绍rust中thread的相关概念、方法和字段、常见用法以及多线程的一些实践经验。由浅入深带你零基础玩转rust的多线程编程。
线程的基本概念和使用方法thread是rust中并发编程的一种基本方式。rust中的thread使用标准库中的std::thread::thread结构体表示。我们可以通过下面的代码来创建一个thread:
use std::thread;fn main() { let handle = thread::spawn(|| { // 子线程执行的代码 });}其中的||表示闭包,该闭包中的代码将在子线程中执行。调用thread::spawn方法会返回一个result,该result包含一个智能指针,该智能指针拥有对线程的所有权,如果线程执行成功则返回ok,否则返回err。通过这个智能指针我们可以管理线程的生命周期和操作线程。
当线程中的代码执行完毕时,我们可以使用以下代码将线程加入主线程:
handle.join().expect(执行失败);thread也支持通过std::thread::builder结构体进行创建,builder提供了一些线程的配置项,如线程名字、线程优先级、栈大小等。
use std::thread;fn main() { let builder = thread::builder::new().name(my_thread.into()); let handle = builder.spawn(|| { // 子线程执行的代码 });}线程的字段和方法thread结构体中提供了一些有用的字段和方法。
线程名称rust中的thread对象有一个名称属性,可以通过thread::current()函数获取当前线程的名称,也可以通过std::thread::builder结构体设置线程的名称。
use std::thread;fn main() { let thr0 = thread::current(); let thread_name = thr0.name().unwrap_or(unknown); println!(当前线程的名称:{}, thread_name); let builder = thread::builder::new().name(my_thread.into()); let handle = builder.spawn(move || { let thr = thread::current(); let name = thr.name().unwrap_or(unknown); println!(当前线程的名称:{}, name); }); handle.expect(执行失败).join().unwrap();}// 输出结果:// 当前线程的名称:main// 当前线程的名称:my_thread线程idrust中的thread对象还有一个id属性,可以通过thread::current()函数获取当前线程的id,也可以通过std::thread::builder结构体设置线程的id。
use std::thread;fn main() { let thread_id = thread::current().id(); println!(当前线程的id:{:?}, thread_id); let builder = thread::builder::new().name(my_thread.into()); let handle = builder.spawn(|| { let id = thread::current().id(); println!(当前线程的id:{:?}, id); }); handle.expect(执行失败).join().unwrap();}// 输出结果:// 当前线程的id:threadid(1)// 当前线程的id:threadid(2)线程休眠rust中thread对象提供了一个sleep方法,用于让线程休眠指定时间。
use std::{thread, time};fn main() { println!(线程休眠前:{:?}, time::instant::now()); thread::sleep(time::duration::from_secs(2)); println!(线程休眠后:{:?}, time::instant::now());}// 输出结果:// 线程休眠前:instant { tv_sec: 9667960, tv_nsec: 471430161 }// 线程休眠后:instant { tv_sec: 9667962, tv_nsec: 471515229 }线程状态rust中thread对象表示的是系统中的一个线程,可以通过thread::joinhandle结构体的is_finalized()和thread::thread的panicking()方法来查看线程是否结束和是否因panic而结束。
use std::thread;fn main() { let handle = thread::spawn(|| { // todo: 执行耗费时间的任务 }); while !handle.is_finished() { thread::sleep_ms(100); } if thread::panicking() { println!(线程因panic而结束); } else { println!(线程正常结束); }}常用用法和示例单线程执行我们可以使用thread开启一个单线程,并在该线程中执行我们的代码。当该线程执行完毕后,我们通过joinhandle.join()方法将该线程加入主线程。
use std::thread;fn main() { let handle = thread::spawn(|| { println!(hello thread!); }); handle.join().unwrap();}多线程执行我们可以使用多个thread对象并行地执行任务,实现多线程编程。
use std::thread;fn main() { let handle1 = thread::spawn(|| { for i in 0..5 { println!(thread1: {}, i); } }); let handle2 = thread::spawn(|| { for i in 0..5 { println!(thread2: {}, i); } }); handle1.join().unwrap(); handle2.join().unwrap();}线程间通信rust中线程间通信可以通过channel实现。在以下例子中,我们开启两个线程,一个线程向channel发送数据,另一个线程从channel接收数据。两个线程可以通过channel实现数据共享和交换。
use std::thread;use std::sync::mpsc;fn main() { let (tx, rx) = mpsc::channel(); let handle1 = thread::spawn(move || { tx.send(hello thread!.to_string()).unwrap(); }); let handle2 = thread::spawn(move || { let msg = rx.recv().unwrap(); println!({}, msg); }); handle1.join().unwrap(); handle2.join().unwrap();}进阶用法:多线程协作和锁多线程协作当线程之间需要协作执行任务时,我们可以通过rust中提供的互斥锁mutex和读写锁rwlock来实现。
以下是一个简单的例子,在这个例子中我们开启两个线程,一个线程向共享变量加1,另一个线程向共享变量减1。由于有两个线程同时修改共享变量,我们需要使用mutex来进行加锁和解锁操作。
use std::sync::{arc, mutex};use std::thread;fn main() { let shared_count = arc::new(mutex::new(0)); let thread1 = shared_count.clone(); let handle1 = thread::spawn(move || { for _ in 0..10 { let mut count = thread1.lock().unwrap(); *count += 1; } }); let thread2 = shared_count.clone(); let handle2 = thread::spawn(move || { for _ in 0..10 { let mut count = thread2.lock().unwrap(); *count -= 1; } }); handle1.join().unwrap(); handle2.join().unwrap(); println!(shared_count: {:?}, *shared_count.lock().unwrap());}// 输出结果:// shared_count: 0锁在多线程编程中,锁是一种常见的同步机制,它用于保护共享数据不受到并发访问的影响。rust标准库中提供了锁的实现mutex、rwlock、barrier、condvar等等。
mutexmutex是rust中最基本的锁机制,它提供了互斥访问的机制。当多个线程同时对一个共享资源进行访问时,mutex会对该资源进行加锁,当一个线程访问该资源时,其他线程无法访问该资源,直到该线程解锁该资源。
use std::sync::{arc, mutex};use std::thread;fn main() { let shared_data = arc::new(mutex::new(0)); let thread1 = shared_data.clone(); let handle1 = thread::spawn(move || { for _ in 0..10 { let mut data = thread1.lock().unwrap(); *data += 1; } }); let thread2 = shared_data.clone(); let handle2 = thread::spawn(move || { for _ in 0..10 { let mut data = thread2.lock().unwrap(); *data -= 1; } }); handle1.join().unwrap(); handle2.join().unwrap(); println!(shared_data: {:?}, *shared_data.lock().unwrap());}// 输出结果:// shared_data: 0rwlockrwlock是一种读写锁,它提供了两种访问方式:读取访问和写入访问,当同时有多个读操作时,rwlock会共享锁,允许多个线程同时访问该数据,当进行写操作时,rwlock会对该数据进行排它锁,只允许一个线程进行访问。
use std::sync::{arc, rwlock};use std::thread;fn main() { let shared_data = arc::new(rwlock::new(0)); let thread1 = shared_data.clone(); let handle1 = thread::spawn(move || { for _ in 0..10 { let mut data = thread1.write().unwrap(); *data += 1; } }); let thread2 = shared_data.clone(); let handle2 = thread::spawn(move || { for _ in 0..10 { let data = thread2.read().unwrap(); println!(data: {:?}, *data); } }); handle1.join().unwrap(); handle2.join().unwrap(); println!(shared_data: {:?}, *shared_data.read().unwrap());}// 输出结果:// data: 10// data: 10// data: 10// data: 10// data: 10// data: 10// data: 10// data: 10// data: 10// data: 10// shared_data: 10rwlock还提供了一个try_read()方法,可以进行非阻塞式的读操作。
barrierbarrier是一种同步机制,它提供了一个点,当多个线程只有在该点处到达才能继续执行。barrier有一个计数器,当计数器到达值n时,所有在该barrier处等待的线程可以继续执行。
use std::sync::{arc, barrier};use std::thread;fn main() { let barrier = arc::new(barrier::new(3)); let thread1 = barrier.clone(); let handle1 = thread::spawn(move || { println!(thread1 step1.); thread1.wait(); println!(thread1 step2.); }); let thread2 = barrier.clone(); let handle2 = thread::spawn(move || { println!(thread2 step1.); thread2.wait(); println!(thread2 step2.); }); handle1.join().unwrap(); handle2.join().unwrap();}// 输出结果:// thread1 step1.// thread2 step1.// error timeout最佳实践:安全地使用thread在使用thread进行多线程编程时,为了保证线程安全,我们需要注意以下几点:
• 在多线程程序中避免使用静态变量,单例模式和全局变量,这些变量可能被多个线程同时访问。• 在多线程编程中,一定要避免使用裸指针和内存共享,这种方式可能导致数据竞争和未定义行为。• 使用rust的锁机制mutex和rwlock等,保证共享数据的线程安全性。• 编写多线程程序时,应该考虑线程池的设计,防止创建过多的线程带来的资源错乱和性能损失。• 多线程程序的并发度一定要注意控制,过高的并发度反而会导致性能下降。以上都是在使用thread时应该注意的一些安全问题,遵循这些原则可以提高多线程程序的可维护性和安全性。
总结本章节通过代码示例深入的探讨了rust中thread的线程的基本概念,线程的字段和方法,常用用法和示例,多线程协作和锁以及thread最佳实践经验。
英飞凌推出业界首款用于实现安全无线充电的身份验证解决方案OPTIGATM Trust Charge
基于EP2C8Q208C7和AD9858实现雷达信号源的应用方案
数控直流稳压电源设计方案
防雷接地所依据的标准和规范
荣耀9什么时候上市?华为荣耀9曝光:麒麟965+1200万像素,价格死磕小米6
Rust的多线程编程概念和使用方法
智能大棚控制系统助力智慧农业领域闯出新天地
电动车电池点焊机优点介绍
智能魔镜的用处有多大,它究竟有什么“魔力”
一文解析运算放大器的简易测量Vos
4个月跨越14城,2019唯样全国巡回研讨会邀你参与!
小寻儿童电话手表A5怎么样 性价比高用料考究
是德科技推出U5303A 12位PCle高速数据采集卡
英特尔正式公布了2019财年第二季度财报
AMD全面看涨 公司获益匪浅
基于NB-IoT无线传输的茶园生境监测DTU技术
关于高耗能企业能耗在线监测系统的建设方案
基于单片机和CAN控制器实现现场智能节点的设计
基于ADS的基站功率放大器仿真实现[图]
2月份全球半导体销售额同比增长56%