Rust标准库学习-Send和Sync

本文介绍了并发编程中的Send和Sync特性,它们在标准库中的作用以及如何确保内存安全。Send用于支持异步环境中的所有权转移,Sync则保证类型可以被安全引用。实现这些特性能绕过编译器约束,但可能导致运行时未定义行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

并发是一个语言及其标准库无法回避的问题,常见的编程语言,到讨论并发之前,都是非常简单易上手的,(当然这点rust有些例外,rust的所有权、引用、生命周期一般是更早的卡点),并发平等的压制着所有语言,让Bug开始出现在初学者的代码中。人也只有一颗脑袋,并发的复杂性并不出人意料。

并发的议题很多,这里分享并发相关的两个频繁出现在标准库中的特征,Send和Sync。

Send和Sync在标准库中的位置是std::marker。

marker里的特征多少带点魔法,意思是这些特征该由哪些类型去实现,都是由编译器去推断或内定的,某个类型不支持某个marker特征,是编译器的约束,根本原因是避免潜在的内存安全问题。

Send

实现Send的类型,才能够在异步环境间进行所有权转移。所说的异步环境,可以是主线程和子线程,也可能是异步运行时的不同Task。标准库中只有少量类型标记为!Send,即不支持Send,例如Rc<T>,Cell<T>系列,可以在marker包中查阅。

在T支持Send的情况下,&T也是支持Send的,不过由于生命周期问题,通常写不出简单的异步传递&T的的代码,生命周期检查不会允许异步随意传递引用,除非这个引用是'static的。通常使用Arc<T>代替&T即可。

Send特征默认有结构传递性,即有Send组合而成的类型也是可Send的。

Sync

提示编译器,实现Sync的类型可以安全地被异步环境进行引用。如果T实现了Sync,那么他的引用&T(或类似引用Box<T>)都是支持Send的(可移交所有权)。更像是对Send进行更底层的一种保证。同样,Sync也是结构传递的,组成Sync的类型也是可Sync的。

一段内存是否可以被异步环境共享,是一种编译器约束,为了杜绝某些可能性而设置的marker。

实现Send或Sync

实现Send或Sync,直接意味着跳过编译器约束,会使潜在问题从编译错误转换成运行时的未定义行为(undefined behavior)。因此,虽然实现这两个特征什么都不用做(特征没有具体方法),但是更需要谨慎对待和思考,其在多线程环境下的表现。

最后放一段多线程执行累加的代码,注意其中Arc和Mutex在异步环境中的使用

    let counter = Mutex::new(0);
    let arc = Arc::new(counter);
    let mut handlers = vec![];
    for _ in 0..100 {
        let arc_current = arc.clone();
        let h = thread::spawn(move||{
            let mut local_counter = arc_current.lock().unwrap();
            *local_counter += 1;
        });
        handlers.push(h);
    }

    for h in handlers {
        h.join().unwrap();
    }
    println!("counter {}", arc.lock().unwrap())

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值