The Dining Philosophers is this correct

I tried to solve The Dining Philosophers Problem using mutex, arc, condvar. does this satasfies the solution?

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


struct ResourcePool {
    resources: Mutex<Vec<bool>>,
    available: Condvar,
}

impl ResourcePool {
    fn new(size: usize) -> ResourcePool {
        ResourcePool {
            resources: Mutex::new(vec![true; size]),
            available: Condvar::new(),
        }
    }

    fn acquire(&self) -> Vec<usize> {
        let mut resourses = self.resources.lock().unwrap();

        loop {
            if let Some(index) = find_available_resources(&resourses, 1) {
                mark_resourcs_as_unavailable(&mut resourses, &index);
                return index;
            }
            resourses = self.available.wait(resourses).unwrap();
        }
    }

    fn release(&self, index: Vec<usize>) {
        let mut resources = self.resources.lock().unwrap();
        for i in index {
            resources[i] = true;
        }
        self.available.notify_all();
    }


}

fn find_available_resources(resources: &Vec<bool>, count: usize) -> Option<Vec<usize>> {
    let mut index = Vec::new();
    // println!("resources ???? {:?}", resources);

    for i in 0..resources.len() {
        if resources[i] {
            // println!("free = {}", i);
            index.push(i);
            if index.len() == count {
                return Some(index);
            }
        } 
    }
    None
}

fn mark_resourcs_as_unavailable(resources: &mut Vec<bool>, index: &Vec<usize>) {
    for i in index {
        resources[*i] = false;
    }
}

pub fn main() {
    let pool = Arc::new(ResourcePool::new(5));
    let mut handles = vec![];

    for i in 0..5 {
        let pool = Arc::clone(&pool);
        let handle = thread::spawn(move || {
            let index = pool.acquire();
            let index2 = pool.acquire();
            println!("thread {} acquired resources {:?} {:?}", i, index, index2);
            thread::sleep(std::time::Duration::from_secs(2));
            pool.release(index.clone());
            pool.release(index2.clone());
            println!("thread {} released resource {:?} {:?}", i, index, index2);
        });
        handles.push(handle);
    }

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

You don't satisfy the problem. You have no left and rights.

It's unclear see what the analogue for the philosophers and forks are here. You might want to make that more explicit; for example:

fn main() {
    const N: usize = 5;
    const STEPS: usize = 3;
    let events = sim::dining_sim(5, &|mut philosopher, left, right| {
        // NB: This solution doesn't work! Replace with your own.
        for _ in 0..STEPS {
            let Some(mut l) = left.take() else { philosopher.think(); continue };
            if let Some(mut r) = right.take() {
                philosopher.eat(&mut l, &mut r);
                right.replace(r);
            }
            left.replace(l);
            philosopher.think();
        }
    });

    let mut eat_counts = vec![0; N];
    let mut think_counts = vec![0; N];

    for (act, id, _) in events {
        match act {
            sim::Action::Eat => eat_counts[id] += 1,
            sim::Action::Think => think_counts[id] += 1,
        }
    }

    dbg!(eat_counts);
    dbg!(think_counts);
}

/// Simulation of dining philosophers
mod sim {
    use rand::{self, Rng};
    use std::sync::mpsc;
    use std::sync::Mutex;
    use std::thread;
    use std::time::{Duration, Instant}; // 0.8.5

    const MIN_DELAY: u64 = 100;
    const MAX_DELAY: u64 = 400;

    fn wait() {
        let t = Duration::from_millis(
            rand::thread_rng().sample(rand::distributions::Uniform::new(MIN_DELAY, MAX_DELAY)),
        );
        thread::sleep(t);
    }

    #[derive(Debug)]
    #[non_exhaustive]
    pub struct Fork;
    pub struct ForkSlot(Mutex<Option<Fork>>);

    impl ForkSlot {
        pub fn take(&self) -> Option<Fork> {
            let mut opt = self.0.lock().unwrap();
            wait();
            opt.take()
        }

        pub fn replace(&self, fork: Fork) -> Option<Fork> {
            let mut opt = self.0.lock().unwrap();
            wait();
            opt.replace(fork)
        }
    }

    #[derive(Debug, Copy, Clone)]
    pub enum Action {
        Eat,
        Think,
    }

    pub struct Philosopher {
        id: usize,
        channel: mpsc::Sender<(Action, usize, Instant)>,
    }

    impl Philosopher {
        pub fn eat(&mut self, _l: &mut Fork, _r: &mut Fork) {
            self.channel
                .send((Action::Eat, self.id, Instant::now()))
                .unwrap();
            wait();
        }

        pub fn think(&mut self) {
            self.channel
                .send((Action::Think, self.id, Instant::now()))
                .unwrap();
            wait();
        }
    }

    pub fn dining_sim(
        n: usize,
        algo: &(impl Send + Sync + Fn(Philosopher, &ForkSlot, &ForkSlot)),
    ) -> Vec<(Action, usize, Instant)> {
        let mut forks = vec![];
        for _ in 0..n {
            forks.push(ForkSlot(Mutex::new(Some(Fork))))
        }
        let (send, recv) = mpsc::channel();
        let forks: &[ForkSlot] = forks.as_ref();
        thread::scope(|scope| {
            for i in 0..n {
                let channel = send.clone();
                scope.spawn(move || {
                    algo(
                        Philosopher { id: i, channel },
                        &forks[i],
                        &forks[(i + 1) % n],
                    )
                });
            }
        });
        std::mem::drop(send);

        recv.into_iter().collect()
    }
}
1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.