news 2026/6/12 8:31:57

【Rust】17-Send、Sync 与并发安全抽象

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【Rust】17-Send、Sync 与并发安全抽象

Send、Sync 与并发安全抽象

研究目标

  • 理解SendSync如何表达跨线程安全。
  • 区分所有权转移、共享引用和内部可变性。
  • 掌握 Rust 并发抽象背后的类型约束。

Rust 并发安全的基础

Rust 的并发安全不是来自某个单独的锁库,而是所有权、借用和类型系统共同作用的结果。核心原则是:

  • 数据可以被移动到另一个线程,但必须安全。
  • 数据可以被多个线程共享引用,但共享访问必须安全。
  • 可变共享需要同步原语或原子操作。

SendSync是两个标记 trait,用于表达这些性质。

Send

Send表示一个类型的值可以安全地转移到另一个线程。

usestd::thread;fnmain(){lettext=String::from("hello");lethandle=thread::spawn(move||{println!("{text}");});handle.join().unwrap();}

StringSend,所以可以通过move闭包转移到新线程。

反例是Rc<T>

usestd::rc::Rc;usestd::thread;fnmain(){letvalue=Rc::new(1);// thread::spawn(move || {// println!("{value}");// });}

Rc<T>的引用计数更新不是线程安全的,所以它不是Send

Sync

Sync表示一个类型可以安全地被多个线程通过共享引用访问。形式化地说,如果&TSend,那么TSync

i32StringVec<T>在合适条件下都是Sync,因为多个线程共享不可变引用读取它们是安全的。

RefCell<T>不是Sync

usestd::cell::RefCell;fnmain(){letvalue=RefCell::new(1);*value.borrow_mut()+=1;}

RefCell<T>的借用计数是非线程安全的运行时检查,不能被多个线程同时访问。

Arc 与 Mutex

跨线程共享所有权通常使用Arc<T>

usestd::sync::Arc;usestd::thread;fnmain(){letvalue=Arc::new(String::from("shared"));letcloned=Arc::clone(&value);lethandle=thread::spawn(move||{println!("{cloned}");});println!("{value}");handle.join().unwrap();}

如果需要跨线程修改共享数据,使用Mutex<T>

usestd::sync::{Arc,Mutex};usestd::thread;fnmain(){letcounter=Arc::new(Mutex::new(0));letmuthandles=Vec::new();for_in0..4{letcounter=Arc::clone(&counter);handles.push(thread::spawn(move||{letmutguard=counter.lock().unwrap();*guard+=1;}));}forhandleinhandles{handle.join().unwrap();}println!("{}",*counter.lock().unwrap());}

Arc<Mutex<T>>的含义是:多个线程共享同一个所有权句柄,每次修改前先获得互斥锁。

RwLock 与读多写少

RwLock<T>允许多个读者或一个写者:

usestd::sync::RwLock;fnmain(){letvalue=RwLock::new(vec![1,2,3]);{letread=value.read().unwrap();println!("{}",read.len());}{letmutwrite=value.write().unwrap();write.push(4);}}

读多写少场景中,RwLock可能比Mutex更合适。但具体性能取决于锁实现、竞争程度和临界区大小。

原子类型

简单计数器可以使用原子类型:

usestd::sync::atomic::{AtomicUsize,Ordering};usestd::sync::Arc;usestd::thread;fnmain(){letcounter=Arc::new(AtomicUsize::new(0));letmuthandles=Vec::new();for_in0..4{letcounter=Arc::clone(&counter);handles.push(thread::spawn(move||{counter.fetch_add(1,Ordering::Relaxed);}));}forhandleinhandles{handle.join().unwrap();}println!("{}",counter.load(Ordering::Relaxed));}

原子操作避免锁,但内存序选择很重要。Relaxed只保证原子性,不建立跨线程同步顺序。复杂并发算法应谨慎使用原子并配合测试和模型检查。

Channel

另一种并发思路是消息传递:

usestd::sync::mpsc;usestd::thread;fnmain(){let(tx,rx)=mpsc::channel();thread::spawn(move||{tx.send(String::from("hello")).unwrap();});letmessage=rx.recv().unwrap();println!("{message}");}

channel 通过移动消息所有权减少共享状态。很多系统可以优先用消息传递表达工作流,只在必要时共享可变状态。

自动实现与 unsafe impl

SendSync通常由编译器自动推导。如果类型的所有字段都是Send,该类型一般也是SendSync也类似。

手写unsafe impl Sendunsafe impl Sync意味着你向编译器承诺这个类型满足跨线程安全不变量:

structMyPointer(*mutu8);// unsafe impl Send for MyPointer {}

这非常危险。除非你完全理解内部别名、生命周期、同步和释放规则,否则不要手写这些实现。

async 中的 Send

异步任务也常遇到Send

tokio::spawn(asyncmove{// future 必须 Send + 'static});

如果 future 跨.await保存了非 Send 值,整个 future 就不是 Send。解决方式包括改用Arc、缩小非 Send 值作用域、使用本地任务执行器。

常见误解

  • Arc<T>只提供线程安全引用计数,不让T自动可变。
  • Mutex<T>保护的是数据访问,不是让逻辑自动无死锁。
  • Send是所有权跨线程转移,Sync是共享引用跨线程访问。
  • RefCell<T>是单线程内部可变性,不是线程同步工具。

继续研究

  • Rustonomicon:Send and Sync。
  • Rust Book:fearless concurrency。
  • Rust Reference:marker traits、undefined behavior、data races。
  • Loom:并发模型测试工具。

后记

2026年6月11日15点23分于上海。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/12 8:31:54

扩散模型在视频生成中的手部与相机控制技术

1. 项目概述&#xff1a;扩散模型在手部与相机控制视频生成中的应用在计算机视觉领域&#xff0c;视频生成技术正经历着革命性的变革。传统方法往往难以同时保证生成质量与精确控制能力&#xff0c;而扩散模型的出现为这一挑战提供了新的解决方案。我们提出的系统专注于一个特定…

作者头像 李华
网站建设 2026/6/12 8:25:58

FPGA入门指南----从可编程逻辑到片上系统

1. FPGA是什么&#xff1f;从芯片到可编程魔法 第一次听说FPGA时&#xff0c;我以为是某种新型CPU的代号。直到亲眼看见同事用它在示波器上实时生成心电图波形&#xff0c;才意识到这玩意儿简直是数字世界的乐高积木。FPGA&#xff08;现场可编程门阵列&#xff09;就像一块空白…

作者头像 李华
网站建设 2026/6/12 8:25:58

Python-docx进阶玩法:手动控制迭代,精准处理Word中的图文表混合内容

Python-docx进阶实战&#xff1a;手动控制文档流处理Word中的复杂元素在文档自动化处理领域&#xff0c;Word文档的精准解析一直是开发者面临的挑战。当我们需要处理包含复杂排版、混合内容&#xff08;如图文表交错&#xff09;的文档时&#xff0c;传统的顺序解析方法往往显得…

作者头像 李华
网站建设 2026/6/12 8:20:50

牛牛和牛可乐的赌约2【牛客tracker 每日一题】

牛牛和牛可乐的赌约2 时间限制&#xff1a;2秒 空间限制&#xff1a;256M 网页链接 牛客tracker 牛客tracker & 每日一题&#xff0c;完成每日打卡&#xff0c;即可获得牛币。获得相应数量的牛币&#xff0c;能在【牛币兑换中心】&#xff0c;换取相应奖品&#xff01;…

作者头像 李华