亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

你怎么能在鐵銹里做一個安全的靜電單例?

你怎么能在鐵銹里做一個安全的靜電單例?

你怎么能在鐵銹里做一個安全的靜電單例?這是一個有爭議的話題,所以讓我先解釋一下我的用例,然后談談實際的問題。我發現對于一堆不安全的事情,確保不泄漏內存是很重要的;如果您開始使用transmute()和forget()..例如,將一個盒裝實例傳遞給C代碼,時間長短任意,然后取出它,然后使用transmute.假設我有一個用于這種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     }}要測試這是其實沒有泄漏任何記憶,我需要這樣的測試:#[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();     }}如何創建這種類型的靜態單例對象?它必須使用Semaphore樣式保護鎖,以確保多個測試不并發運行,然后不安全地訪問某種靜態可變值。我想也許這樣的實施是可行的,但實際上,它失敗了,因為有時爭用條件會導致重復執行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));     }}特別要注意的是,不同于普通程序,您可以確定入口點(Main)總是在單個任務中運行,RUST中的測試運行程序不提供任何這樣的單一入口點。顯然,除了指定任務的最大數量之外,如果有幾十個測試,那么只需要做幾個這樣的事情,并且只在這一種情況下將測試任務池限制為一個是緩慢和毫無意義的。
查看完整描述

2 回答

?
慕森王

TA貢獻1777條經驗 獲得超3個贊

它看起來像用例std::sync::Once:

use std::sync::{Once, ONCE_INIT};static INIT: Once = ONCE_INIT;

然后在你的測試中調用

INIT.doit(|| unsafe { init(); });

Once保證你init將只執行一次,不管您調用了多少次。INIT.doit().


查看完整回答
反對 回復 2019-07-12
?
狐的傳說

TA貢獻1804條經驗 獲得超3個贊

另見懶靜這使得事情更符合人體工程學。它所做的與靜態的事情本質上是一樣的。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);}

請注意,autoderef意味著您甚至不必使用*每當您對靜態變量調用方法時。變量將在第一次初始化它的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}


查看完整回答
反對 回復 2019-07-12
  • 2 回答
  • 0 關注
  • 385 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號