2017-11-04 21 views
-1

我在讀The Rustonomicon,並且遇到了它的section on poisoning。一個類型中毒的書面例子是當一個「互斥體將在一個恐慌期間如果它的一個MutexGuard(它獲得鎖定時返回的東西)在一個恐慌期間被丟棄」,「(Rustonomicon,第7.2節第3段)如何演示類型中毒?

我很漂亮,但突然很好奇。

爲了努力尋找類型中毒的實施示範,谷歌搜索「如何毒害一種類型」產生無用的結果,從化學毒物類型列表到口袋妖怪。 「類型中毒的代碼示例」的結果大致相同。

是否有人可以用代碼段來演示類型中毒?我不在乎這個例子是否在Rust中,但也許這很重要......因爲在某些語言中只能以某些方式中毒?

我看到中毒發生在其他語言,或至少C++ function poisoningnamespace poisoning。 (搜索「Java類型中毒」從檢測到java bean poisoned dogshow to poison mobs in Minecraft產生無用但有趣的結果。)

但是這些示例缺少代碼中示例的鏈接。我希望看到它的行動。

+0

嗯......生活和學習......我只是谷歌搜索「鏽型中毒」,發現這個:https://doc.rust-lang.org/std/sync/struct。 Mutex.html – NonCreature0714

+0

這個問題並沒有說清楚你的意思是「用代碼演示類型中毒」。你是在尋找一箇中毒概念*的示範(毒化一個對象的意思,爲什麼有人會這樣做),中毒的一個特殊實現*(例如Rust互斥體中的一個),或者一個例子*使用*毒性類型?弗朗索瓦的回答顯示了Rust最小的完整實現概念。 – user4815162342

+0

的確如此,他的回答確實顯示了MVCE的實施,但我希望在接受之前等待適當的時間。儘管讓某個人展示中毒概念以及爲什麼可以故意完成這將是非常有用的,但這不是我所要求的,所以我會澄清一下。 – NonCreature0714

回答

3

通過在Drop實施中檢查std::thread::panicking的返回值來實施中毒。如果它返回true,則該值應該中毒。這裏有一個例子:

use std::cell::Cell; 
use std::panic::{self, AssertUnwindSafe}; 
use std::thread; 

#[derive(Clone, Copy, Debug, PartialEq, Eq)] 
enum ResourceState { 
    Available, 
    Locked, 
    Poisoned, 
} 

struct Resource { 
    state: Cell<ResourceState>, 
} 

struct ResourceGuard<'a> { 
    resource: &'a Resource, 
} 

impl Resource { 
    fn new() -> Resource { 
     Resource { 
      state: Cell::new(ResourceState::Available), 
     } 
    } 

    fn lock(&self) -> ResourceGuard { 
     assert_eq!(self.state.get(), ResourceState::Available); 
     self.state.set(ResourceState::Locked); 
     ResourceGuard { 
      resource: self, 
     } 
    } 
} 

impl<'a> Drop for ResourceGuard<'a> { 
    fn drop(&mut self) { 
     self.resource.state.set(
      if thread::panicking() { 
       ResourceState::Poisoned 
      } else { 
       ResourceState::Available 
      }); 
    } 
} 

fn main() { 
    let resource = Resource::new(); 
    println!("state: {:?}", resource.state.get()); // Available 

    { 
     println!("acquiring lock"); 
     let _guard = resource.lock(); 
     println!("state: {:?}", resource.state.get()); // Locked 
     println!("dropping lock"); 
    } 

    println!("state: {:?}", resource.state.get()); // Available 

    let _ = panic::catch_unwind(AssertUnwindSafe(|| { 
     println!("acquiring lock"); 
     let _guard = resource.lock(); 
     println!("state: {:?}", resource.state.get()); // Locked 
     println!("panicking!"); 
     panic!("panicking!"); 
    })); 

    println!("state: {:?}", resource.state.get()); // Poisoned 
}