慕蓋茨4494581
2019-07-12 15:28:31
你怎么能在鐵銹里做一個(gè)安全的靜電單例?這是一個(gè)有爭(zhēng)議的話題,所以讓我先解釋一下我的用例,然后談?wù)剬?shí)際的問(wèn)題。我發(fā)現(xiàn)對(duì)于一堆不安全的事情,確保不泄漏內(nèi)存是很重要的;如果您開(kāi)始使用transmute()和forget()..例如,將一個(gè)盒裝實(shí)例傳遞給C代碼,時(shí)間長(zhǎng)短任意,然后取出它,然后使用transmute.假設(shè)我有一個(gè)用于這種API的安全包裝器:trait Foo {}struct CBox;impl CBox {
/// Stores value in a bound C api, forget(value)
fn set<T: Foo>(value: T) {
// ...
}
/// Periodically call this and maybe get a callback invoked
fn poll(_: Box<Fn<(EventType, Foo), ()> + Send>) {
// ...
}}impl Drop for CBox {
fn drop(&mut self) {
// Safely load all saved Foo's here and discard them, preventing memory leaks
}}要測(cè)試這是其實(shí)沒(méi)有泄漏任何記憶,我需要這樣的測(cè)試:#[cfg(test)]mod test {
struct IsFoo;
impl Foo for IsFoo {}
impl Drop for IsFoo {
fn drop(&mut self) {
Static::touch();
}
}
#[test]
fn test_drops_actually_work() {
guard = Static::lock(); // Prevent any other use of Static concurrently
Static::reset(); // Set to zero
{
let c = CBox;
c.set(IsFoo);
c.set(IsFoo);
c.poll(/*...*/);
}
assert!(Static::get() == 2); // Assert that all expected drops were invoked
guard.release();
}}如何創(chuàng)建這種類型的靜態(tài)單例對(duì)象?它必須使用Semaphore樣式保護(hù)鎖,以確保多個(gè)測(cè)試不并發(fā)運(yùn)行,然后不安全地訪問(wèn)某種靜態(tài)可變值。我想也許這樣的實(shí)施是可行的,但實(shí)際上,它失敗了,因?yàn)橛袝r(shí)爭(zhēng)用條件會(huì)導(dǎo)致重復(fù)執(zhí)行init:/// Global instancestatic mut INSTANCE_LOCK: bool = false;static mut INSTANCE: *mut StaticUtils = 0 as
*mut StaticUtils;static mut WRITE_LOCK: *mut Semaphore = 0 as *mut Semaphore;static mut LOCK: *mut Semaphore = 0 as *mut Semaphore;
/// Generate instances if they don't existunsafe fn init() {
if !INSTANCE_LOCK {
INSTANCE_LOCK = true;
INSTANCE = transmute(box StaticUtils::new());
WRITE_LOCK = transmute(box Semaphore::new(1));
LOCK = transmute(box Semaphore::new(1));
}}特別要注意的是,不同于普通程序,您可以確定入口點(diǎn)(Main)總是在單個(gè)任務(wù)中運(yùn)行,RUST中的測(cè)試運(yùn)行程序不提供任何這樣的單一入口點(diǎn)。顯然,除了指定任務(wù)的最大數(shù)量之外,如果有幾十個(gè)測(cè)試,那么只需要做幾個(gè)這樣的事情,并且只在這一種情況下將測(cè)試任務(wù)池限制為一個(gè)是緩慢和毫無(wú)意義的。
2 回答

慕森王
TA貢獻(xiàn)1777條經(jīng)驗(yàn) 獲得超3個(gè)贊
std::sync::Once
:
use std::sync::{Once, ONCE_INIT};static INIT: Once = ONCE_INIT;
INIT.doit(|| unsafe { init(); });
Once
init
INIT.doit()
.

狐的傳說(shuō)
TA貢獻(xiàn)1804條經(jīng)驗(yàn) 獲得超3個(gè)贊
Once
Deref
#[macro_use]extern crate lazy_static;use std::collections::HashMap;lazy_static! { static ref HASHMAP: HashMap<u32, &'static str> = { let mut m = HashMap::new(); m.insert(0, "foo"); m.insert(1, "bar"); m.insert(2, "baz"); m }; static ref COUNT: usize = HASHMAP.len(); static ref NUMBER: u32 = times_two(21);}fn times_two(n: u32) -> u32 { n * 2 }fn main() { println!("The map has {} entries.", *COUNT); println!("The entry for `0` is \"{}\".", HASHMAP.get(&0).unwrap()); println!("A expensive calculation on a static results in: {}.", *NUMBER);}
*
Deref
Mutex
:
lazy_static! { static ref VALUE: Mutex<u64>;}impl Drop for IsFoo { fn drop(&mut self) { let mut value = VALUE.lock().unwrap(); *value += 1; }}#[test]fn test_drops_actually_work() { // Have to drop the mutex guard to unlock, so we put it in its own scope { *VALUE.lock().unwrap() = 0; } { let c = CBox; c.set(IsFoo); c.set(IsFoo); c.poll(/*...*/); } assert!(*VALUE.lock().unwrap() == 2); // Assert that all expected drops were invoked}
添加回答
舉報(bào)
0/150
提交
取消