2015-08-10 17 views
6

, Yemek Filozoflar sorunun kendi mutekslere dayalı uygulama her zaman yaparak, yani her filozofun sol çatal gibi düşük kimlik çatalını seçerek kilitlenme önüne geçtiği bir solak:Yanlış yapıldığında neden yemek filozofları çıkmazda egzersiz yapmıyor? <a href="https://doc.rust-lang.org/book/dining-philosophers.html" rel="nofollow">Rust exercise docs</a> göre

let philosophers = vec![ 
     Philosopher::new("Judith Butler", 0, 1), 
     Philosopher::new("Gilles Deleuze", 1, 2), 
     Philosopher::new("Karl Marx", 2, 3), 
     Philosopher::new("Emma Goldman", 3, 4), 
     Philosopher::new("Michel Foucault", 0, 4), 
    ]; 

Ancak, bu kurala uymazsam ve son Philosopher'daki çatal indekslerini değiştirirsem, program hala kilitlenme veya panikleme olmadan çalışır.

başka şeyler denedim:

  • sonunda
  • olacağını görmek için bir loop{} ana gövdeyi tamamlayan uyku argüman
  • dışarı yorumlarında eat() işlev çağrısı
  • uyku argümanı Uzatma

Bunu düzgün bir şekilde kırmak için ne yapmalıyım? Ne yazık ki şimdiki Pas dokümanlar Bu örneği içermez, bu nedenle yukarıdaki bağlantı bozulur:

use std::thread; 
use std::sync::{Mutex, Arc}; 

struct Philosopher { 
    name: String, 
    left: usize, 
    right: usize, 
} 

impl Philosopher { 
    fn new(name: &str, left: usize, right: usize) -> Philosopher { 
     Philosopher { 
      name: name.to_string(), 
      left: left, 
      right: right, 
     } 
    } 

    fn eat(&self, table: &Table) { 
     let _left = table.forks[self.left].lock().unwrap(); 
     let _right = table.forks[self.right].lock().unwrap(); 

     println!("{} is eating.", self.name); 

     thread::sleep_ms(1000); 

     println!("{} is done eating.", self.name); 
    } 
} 

struct Table { 
    forks: Vec<Mutex<()>>, 
} 

fn main() { 
    let table = Arc::new(Table { forks: vec![ 
     Mutex::new(()), 
     Mutex::new(()), 
     Mutex::new(()), 
     Mutex::new(()), 
     Mutex::new(()), 
    ]}); 

    let philosophers = vec![ 
     Philosopher::new("Judith Butler", 0, 1), 
     Philosopher::new("Gilles Deleuze", 1, 2), 
     Philosopher::new("Karl Marx", 2, 3), 
     Philosopher::new("Emma Goldman", 3, 4), 
     Philosopher::new("Michel Foucault", 0, 4), 
    ]; 

    let handles: Vec<_> = philosophers.into_iter().map(|p| { 
     let table = table.clone(); 

     thread::spawn(move || { 
      p.eat(&table); 
     }) 
    }).collect(); 

    for h in handles { 
     h.join().unwrap(); 
    } 
} 

PS:


İşte yukarıdaki değişikliklerin hiçbirini olmadan tam kaynağıdır.

cevap

8

Her filozof "eşzamanlı olarak" solundaki çatalı kaldırdığında ve sonra sağındaki çatağın zaten alındığını bulduğunda çıkmaz ortaya çıkar. Bunu ihmal edilemez bir şekilde sık sık yapmak için, bazı uyuşmazlık faktörlerini "eşzamanlılık" a tanıtmanız gerekir, böylece eğer filozoflar sol çatallarını birbirlerinin belirli bir zaman diliminde toplarlarsa, hiçbirinin Doğru çatallarını almak için. Diğer bir deyişle, iki çatal alıp arasındaki uyku biraz tanıtmak gerekir:

fn eat(&self, table: &Table) { 
     let _left = table.forks[self.left].lock().unwrap(); 
     thread::sleep_ms(1000);  // <---- simultaneity fudge factor 
     let _right = table.forks[self.right].lock().unwrap(); 

     println!("{} is eating.", self.name); 

     thread::sleep_ms(1000); 

     println!("{} is done eating.", self.name); 
    } 

(değil garanti bir kilitlenme, sadece çok daha olası hale getirir Tabii bu gelmez.

+0

Harika. Bu çıkmazlar hemen gider ve endeksleri tersine çevirmek, kilitlenmenin gerçekleşmesini kesinlikle önler. –

+0

Parlak ve basit. Bu belgelere kopyalanmalıdır – tafia

İlgili konular