本文簡要介紹rust語言中 Struct alloc::sync::Arc
的用法。
用法
pub struct Arc<T: ?Sized> { /* fields omitted */ }
線程安全的引用計數指針。 'Arc' 代表“原子引用計數”。
Arc<T>
類型提供在堆中分配的類型為 T
的值的共享所有權。在 Arc
上調用 clone
會生成一個新的 Arc
實例,該實例指向堆上與源 Arc
相同的分配,同時增加引用計數。當指向給定分配的最後一個Arc
指針被銷毀時,存儲在該分配中的值(通常稱為“inner value”)也將被刪除。
Rust 中的共享引用默認不允許突變,Arc
也不異常:您通常無法獲取對 Arc
內部某些內容的可變引用。如果您需要通過 Arc
進行變異,請使用 Mutex
、 RwLock
或 Atomic
類型之一。
線程安全
與 Rc<T>
不同,Arc<T>
使用原子操作進行引用計數。這意味著它是線程安全的。缺點是原子操作比普通的內存訪問更昂貴。如果您不在線程之間共享reference-counted 分配,請考慮使用 Rc<T>
來降低開銷。 Rc<T>
是一個安全的默認值,因為編譯器將捕獲任何在線程之間發送 Rc<T>
的嘗試。但是,庫可能會選擇Arc<T>
,以便為庫使用者提供更大的靈活性。
隻要 T
實現 Send
和 Sync
,Arc<T>
就會實現 Send
和 Sync
。為什麽不能將非線程安全類型 T
放入 Arc<T>
中以使其成為線程安全?乍一看這可能有點counter-intuitive:畢竟,Arc<T>
線程安全的重點不是嗎?關鍵是:Arc<T>
使得對同一數據具有多個所有權是線程安全的,但它並沒有為其數據添加線程安全性。考慮Arc<RefCell<T>>
。 RefCell<T>
不是 Sync
,如果 Arc<T>
始終是 Send
,則 Arc<RefCell<T>>
也是如此。但這樣我們就會遇到一個問題: RefCell<T>
不是線程安全的;它使用非原子操作跟蹤借用計數。
最後,這意味著您可能需要將 Arc<T>
與某種 std::sync
類型配對,通常是 Mutex<T>
。
使用Weak
中斷循環
alloc::sync::Arc.downgrade方法可用於創建非擁有Weak
指針。 AWeak
指針可以是alloc::sync::Weak.upgraded 至Arc
,但這會返回None
如果存儲在分配中的值已被刪除。換句話說,Weak
指針不會使分配內的值保持活動狀態;然而,他們做保持分配(值的後備存儲)處於活動狀態。
Arc
指針之間的循環永遠不會被釋放。因此, Weak
用於中斷循環。例如,一棵樹可能具有從父節點到子節點的強 Arc
指針,以及從子節點返回到父節點的 Weak
指針。
克隆參考
使用為 Arc<T>
和 Weak<T>
實現的 Clone
特征從現有的 reference-counted 指針創建新引用。
use std::sync::Arc;
let foo = Arc::new(vec![1.0, 2.0, 3.0]);
// The two syntaxes below are equivalent.
let a = foo.clone();
let b = Arc::clone(&foo);
// a, b, and foo are all Arcs that point to the same memory location
Deref
行為
Arc<T>
自動取消引用 T
(通過 Deref
特征),因此您可以對 Arc<T>
類型的值調用 T
的方法。為了避免與 T
的方法發生名稱衝突,Arc<T>
本身的方法是關聯函數,使用 fully qualified syntax 進行調用:
use std::sync::Arc;
let my_arc = Arc::new(());
let my_weak = Arc::downgrade(&my_arc);
Arc<T>
對 Clone
等特征的實現也可以使用完全限定的語法來調用。有些人喜歡使用完全限定的語法,而另一些人則喜歡使用method-call 語法。
use std::sync::Arc;
let arc = Arc::new(());
// Method-call syntax
let arc2 = arc.clone();
// Fully qualified syntax
let arc3 = Arc::clone(&arc);
Weak<T>
不會自動取消對 T
的引用,因為內部值可能已被刪除。
例子
在線程之間共享一些不可變的數據:
use std::sync::Arc;
use std::thread;
let five = Arc::new(5);
for _ in 0..10 {
let five = Arc::clone(&five);
thread::spawn(move || {
println!("{:?}", five);
});
}
共享一個可變的 AtomicUsize
:
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::thread;
let val = Arc::new(AtomicUsize::new(5));
for _ in 0..10 {
let val = Arc::clone(&val);
thread::spawn(move || {
let v = val.fetch_add(1, Ordering::SeqCst);
println!("{:?}", v);
});
}
有關一般引用計數的更多示例,請參閱 rc 文檔。
相關用法
- Rust Arc.assume_init用法及代碼示例
- Rust Arc.make_mut用法及代碼示例
- Rust Arc.try_new用法及代碼示例
- Rust Arc.increment_strong_count用法及代碼示例
- Rust Arc.decrement_strong_count用法及代碼示例
- Rust Arc.try_new_zeroed用法及代碼示例
- Rust Arc.new_uninit_slice用法及代碼示例
- Rust Arc.strong_count用法及代碼示例
- Rust Arc.downcast用法及代碼示例
- Rust Arc.try_unwrap用法及代碼示例
- Rust Arc.get_mut_unchecked用法及代碼示例
- Rust Arc.get_mut用法及代碼示例
- Rust Arc.from_raw用法及代碼示例
- Rust Arc.ptr_eq用法及代碼示例
- Rust Arc.new用法及代碼示例
- Rust Arc.weak_count用法及代碼示例
- Rust Arc.new_cyclic用法及代碼示例
- Rust Arc.new_zeroed用法及代碼示例
- Rust Arc.into_raw用法及代碼示例
- Rust Arc.as_ptr用法及代碼示例
- Rust Arc.new_zeroed_slice用法及代碼示例
- Rust Arc.downgrade用法及代碼示例
- Rust Arc.try_new_uninit用法及代碼示例
- Rust Arc.new_uninit用法及代碼示例
- Rust Arguments用法及代碼示例
注:本文由純淨天空篩選整理自rust-lang.org大神的英文原創作品 Struct alloc::sync::Arc。非經特殊聲明,原始代碼版權歸原作者所有,本譯文未經允許或授權,請勿轉載或複製。