Cinco filósofos se sientan alrededor de una mesa y pasan su vida cenando y pensando. Cada filósofo tiene un plato de fideos y un palito chino a la izquierda de su plato.

Para comer los fideos son necesarios dos palitos y cada filósofo sólo puede tomar los que están a su izquierda y derecha.

Si cualquier filósofo toma un palito y el otro está ocupado, se quedará esperando, con el palito en la mano, hasta que pueda tomar el otro palito, para luego empezar a comer.

Problema:

Deadlock → que cada uno tome un palito y que ninguno pueda tomar los dos palitos.

Solución:

Hay un filósofo que es zurdo y agarra al revés del resto, y nunca sucede el deadlock.

extern crate std_semaphore;
extern crate rand;

use std_semaphore::Semaphore;
use std::thread;
use std::time::Duration;
use rand::{thread_rng, Rng};
use std::sync::Arc;
use std::thread::JoinHandle;

const N:usize = 5;

/**
Cinco filósofos se sientan alrededor de una mesa y pasan su vida cenando y pensando.
Cada filósofo tiene un plato de fideos y un palito chino a la izquierda de su plato.
Para comer los fideos son necesarios dos palitos y cada filósofo sólo puede tomar los que
están a su izquierda y derecha. Si cualquier filósofo toma un palito y el otro está ocupado,
se quedará esperando, con el tenedor en la mano, hasta que pueda tomar el otro tenedor,
para luego empezar a comer.
*/

fn main() {
    let chopsticks:Arc<Vec<Semaphore>> = Arc::new((0 .. N)
        .map(|_| Semaphore::new(1))
        .collect());

    let philosophers:Vec<JoinHandle<()>> = (0 .. N)
        .map(|id| {
            let chopsticks_local = chopsticks.clone();
            thread::spawn(move || philosopher(id, chopsticks_local))
        })
        .collect();

    for philosopher in philosophers {
        philosopher.join();
    }

}

fn philosopher(id: usize, chopsticks: Arc<Vec<Semaphore>>) {
    let next = (id + 1) % N;
    let first_chopstick;
    let second_chopstick;

    // solucion al deadlock
    //if id == (N-1) {
    //    first_chopstick = &chopsticks[next];
    //    second_chopstick = &chopsticks[id];
    //} else {
       first_chopstick = &chopsticks[id];
       second_chopstick = &chopsticks[next];
    //}

    // tratar de forzar tomar en el primer palito en el orden de id
    thread::sleep(Duration::from_millis(100 * id as u64));

    loop {
        println!("filosofo {} pensando", id);
        //thread::sleep(Duration::from_millis(thread_rng().gen_range(500, 1500)));
        println!("filosofo {} esperando palito izquierdo", id);
        {
            let first_access = first_chopstick.access();
            // pausa despues del primer palito para forzar el deadlock
            thread::sleep(Duration::from_millis(1000));
            println!("filosofo {} esperando palito derecho", id);
            {
                let second_access = second_chopstick.access();
                println!("filosofo {} comiendo", id);
                thread::sleep(Duration::from_millis(thread_rng().gen_range(500, 1500)));
            }
        }
    }
}

Versión visual

extern crate druid;
extern crate std_semaphore;
extern crate rand;

use druid::{AppLauncher, Data, ImageBuf, PlatformError, Widget, WidgetExt, WindowDesc, ExtEventSink, Selector, Target, AppDelegate, DelegateCtx, Command, Env, Handled};
use druid::widget::{Button, FillStrat, Flex, Image, Label};
use std_semaphore::Semaphore;
use std::sync::Arc;
use std::thread::JoinHandle;
use std::thread;
use std::time::Duration;
use rand::{thread_rng, Rng};
use std::sync::atomic::{AtomicI32, Ordering};
use std::error::Error;
use std::borrow::Borrow;

#[derive(Clone, Data, PartialEq, Debug)] // Debug to easily convert to string
enum PhilosopherState {
    Thinking,
    AwaitingFirstChopstick,
    GotFirstChopstick,
    AwaitingSecondChopstick,
    Eating,
}

struct PhilosopherStateUpdate {
    id: usize,
    state: PhilosopherState,
}

const SET_PHILOSOPHER_STATE: Selector<PhilosopherStateUpdate> = Selector::new("set-philosopher-state");

#[derive(Clone, Data)]
struct AppState {
    states: [PhilosopherState; N],
    clicks: Arc<Vec<Semaphore>>,
}

const images: [&[u8]; 5] = [
    include_bytes!("../img/philo0.png"),
    include_bytes!("../img/philo1.png"),
    include_bytes!("../img/philo2.png"),
    include_bytes!("../img/philo3.png"),
    include_bytes!("../img/philo4.png")
];

const N: usize = 5;

fn main() -> Result<(), PlatformError> {
    // Window builder. We set title and size
    let main_window = WindowDesc::new(ui_builder)
        .title("Filosofos")
        .window_size((800.0, 800.0));

    let launcher = AppLauncher::with_window(main_window).delegate(Delegate {});

    let chopsticks: Arc<Vec<Semaphore>> = Arc::new((0..N)
        .map(|_| Semaphore::new(1))
        .collect());

    let app_state = AppState {
        states: [PhilosopherState::Thinking, PhilosopherState::Thinking, PhilosopherState::Thinking, PhilosopherState::Thinking, PhilosopherState::Thinking],
        clicks: Arc::new((0..N)
            .map(|_| Semaphore::new(0))
            .collect()),
    };

    for id in (0..N) {
        let chopsticks_local = chopsticks.clone();
        let clicks = app_state.clicks.clone();
        let sink = launcher.get_external_handle();
        thread::spawn(move || philosopher(id, chopsticks_local, &clicks[id], sink));
    }

    // Run the app
    launcher.launch(app_state)
}

fn philosopher(id: usize, chopsticks: Arc<Vec<Semaphore>>, await_click: &Semaphore, event_sink: ExtEventSink) {
    let first_chopstick = &chopsticks[id];
    let second_chopstick = &chopsticks[(id + 1) % 5];

    let notify_state = |state: PhilosopherState| event_sink.submit_command(SET_PHILOSOPHER_STATE, PhilosopherStateUpdate { id, state }, Target::Auto);

    loop {
        notify_state(PhilosopherState::Thinking);
        await_click.acquire();

        {
            notify_state(PhilosopherState::AwaitingFirstChopstick);
            let first = first_chopstick.access();
            notify_state(PhilosopherState::GotFirstChopstick);

            // Require another click to be able to test the deadlock
            await_click.acquire();

            {
                notify_state(PhilosopherState::AwaitingSecondChopstick);
                let second = second_chopstick.access();

                notify_state(PhilosopherState::Eating);
                await_click.acquire();
            }
        }
    }
}

fn ui_builder() -> impl Widget<AppState> {
    let mut flex = Flex::column();

    flex.add_child(render_philosopher(0));
    for i in 1..(N/2 + 1) {
        flex.add_child(
            Flex::row()
                .with_child(render_philosopher(N - i))
                .with_spacer(300.0)
                .with_child(render_philosopher(i))
        );
        flex.add_spacer(20.0);
    }

    flex
}

fn render_philosopher(i: usize) -> impl Widget<AppState> {
    Flex::column()
        .with_child(Image::new(ImageBuf::from_data(images[i % N]).unwrap())
            .fill_mode(FillStrat::ScaleDown)
            .fix_height(150.0))
        .with_child(Label::new(move |data: &AppState, _: &_| i.to_string() + " is " + &*format!("{:?}", data.states[i])))
        .with_spacer(1.0)
        .with_child(Button::new("step")
            .on_click(move |_ctx, data: &mut AppState, _env| data.clicks[i].release())
            .padding(5.0))
}

struct Delegate;

impl AppDelegate<AppState> for Delegate {
    fn command(&mut self, _ctx: &mut DelegateCtx, _target: Target, cmd: &Command, data: &mut AppState, _env: &Env) -> Handled {
        if let Some(update) = cmd.get(SET_PHILOSOPHER_STATE) {
            data.states[update.id] = update.state.clone();
            Handled::Yes
        } else {
            Handled::No
        }
    }
}