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.
Deadlock → que cada uno tome un palito y que ninguno pueda tomar los dos palitos.
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)));
}
}
}
}
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
}
}
}