Arc在Rust中是怎么工作的

发布时间:2021-12-22 13:53:10 作者:柒染
来源:亿速云 阅读:100

这篇文章给大家介绍Arc在Rust中是怎么工作的,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。

  原子引用计数(Arc)类型是一种智能指针,它能够让你以线程安全的方式在线程间共享不可变数据。我还没有发现能够很好地解释它的工作原理的文章,所以我决定尝试来写一篇。

第一部分是介绍怎样使用Arc和为什么要使用Arc;如果你已经了解这部分内容,只是想知道它是如何工作的,可以直接跳到第二部分:“它是怎样工作的(How does it work)”。

  为什么你需要使用Arc?当你试图在线程间共享数据时,需要Arc类型来保证被共享的类型的生命周期,与运行时间最长的线程活得一样久。考虑下面的例子:

  use std::thread;use std::time::Duration;fn main() { let foo = vec![0]; 

// creation of foo here thread::spawn(|| { 

thread::sleep(Duration::from_millis(20)); println!("{:?}", &foo); });} 

// foo gets dropped here

// wait 20 milliseconds

// try to print foo

  这段代码无法编译通过。我们会得到一个错误,称foo的引用活得比foo自身更久。这是因为foo在main函数结尾处就被丢弃(drop)了,并且这个被丢弃的值会在20毫秒后在生成的线程中被试图访问。这就是Arc的作用所在。原子引用计数确保在对foo类型的所有引用都结束之前,它不会被丢弃——因此即使在main函数结束之后,foo仍然会存在。现在考虑下面的示例:

  use std::thread;use std::sync::Arc;use std::time::Duration;fn main() { 

let foo = Arc::new(vec![0]); let bar = Arc::clone(&foo); 

thread::spawn(move || { 

thread::sleep(Duration::from_millis(20)); println!("{:?}", *bar); });

 println!("{:?}", foo);}

  在这个例子中,我们可以在(主)线程中引用foo并且还可以在(子)线程被生成之后访问它的值。

  它是怎样工作的?你已经知道如何使用Arc了,现在让我们讨论一下它是如何工作的。当你调用let foo = Arc::new(vec![0])时,你同时创建了一个vec![0]和一个值为1的原子引用计数,并且把它们都存储在堆上的相同位置(紧挨着)。指向堆上的这份数据的指针存放在foo中。因此,foo是由指向一个对象的指针构成,被指向的对象包含vec![0]和原子计数。

  当你调用let bar = Arc::clone(&foo)时,你是在获取foo的一个引用、对foo(指向存放在堆上的数据的指针)解引用、接着找到foo指向的地址、找出里面存放的值(vec![0]和原子计数)、把原子计数加一、最后把指向vec![0]的指针保存在bar中。

  当foo或bar离开作用域时,Arc::drop()就被调用了,原子计数减一。如果Arc::drop()发现原子计数等于0,那么它所指向的堆上的数据(vec![0]和原子计数)会被清理并从堆上擦除。

  原子计数是一种能够让你以线程安全的方式修改和增加它的值的类型;在对原子类型允许进行其他操作之前,前面的原子类型操作必须要全部完成;因此被称为原子的(atomic)(即不可分割的)(操作)。

  需要注意的是,Arc只能包含不可变数据。这是因为如果两个线程试图在同一时间修改被包含的值,Arc无法保证避免数据竞争。如果你希望修改数据,你应该在Arc类型内部封装一个互斥锁保护(Mutex guard)。

  为什么这些东西能让Arc是线程安全的呢?Arc是线程安全的是因为它给编译器保证数据的引用至少活得和数据本身一样长(译注:这里原作者应该是想表达,数据的引用存在期间,数据都是有效的)。这是因为每次你创建一个对堆上数据得引用,原子计数就会加一,数据只有在当原子计数等于零得时候才会被丢弃(每当一个引用离开作用域时,原子计数会减一)——Arc和一个普通得Rc(引用计数)之间得区别就在于原子计数。

关于Arc在Rust中是怎么工作的就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

推荐阅读:
  1. 在 ARC 环境下使用 dealloc
  2. 在支持ARC工程中编译不支持ARC的文件

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

arc rust

上一篇:Java Reflection的示例分析

下一篇:mysql中出现1053错误怎么办

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》