Hecho por Suhas Patil:
Consideremos que para fumar un cigarrillo se necesitan 3 ingredientes: tabaco, papel y fósforos. Hay 3 fumadores alrededor de una mesa.
Cada uno tiene una cantidad infinita de uno solo de los ingredientes y necesita los otros dos para fumar.
Cada fumador posee un ingrediente distinto. Existe además un agente que pone aleatoriamente dos ingredientes en la mesa.
El fumador que los necesita los tomará para hacer su cigarrillo y fumará un rato.
Cuando el fumador termina, el agente pone otros dos ingredientes.
No se pueden bloquear ambos al mismo tiempo y toman de a uno.

extern crate rand;
extern crate std_semaphore;
extern crate num_derive;
extern crate num_traits;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use rand::{thread_rng};
use rand::seq::SliceRandom;
use std_semaphore::Semaphore;
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use std::thread::JoinHandle;
const N:usize = 3;
#[derive(Clone, Copy, Debug, FromPrimitive)]
enum Ingredients {
Tobacco = 0,
Paper,
Fire
}
const ALL_INGREDIENTS: [Ingredients; N] = [Ingredients::Tobacco, Ingredients::Paper, Ingredients::Fire];
fn main() {
let agent_sem = Arc::new(Semaphore::new(1));
let ingredient_sems: Arc<Vec<Semaphore>> = Arc::new((0..N)
.map(|_| Semaphore::new(0))
.collect());
let agent_sem_a = agent_sem.clone();
let ingredients_sem_a = ingredient_sems.clone();
let agent = thread::spawn(move || loop {
println!("[Agente] Esperando sem");
agent_sem_a.acquire();
let mut ings = ALL_INGREDIENTS.to_vec();
ings.shuffle(&mut thread_rng());
let selected_ings = &ings[0..N-1];
for ing in selected_ings {
println!("[Agente] Pongo {:?}", ing);
ingredients_sem_a[*ing as usize].release();
}
});
let smokers:Vec<JoinHandle<()>> = (0..N)
.map(|i| {
let agent_sem_smoker = agent_sem.clone();
let ingredient_sems_smoker = ingredient_sems.clone();
thread::spawn(move || loop {
let me = Ingredients::from_usize(i).unwrap();
for ing_id in 0..N {
if ing_id != i {
let ing = Ingredients::from_usize(ing_id).unwrap();
println!("[Fumador {:?}] Esperando {:?}", me, ing);
ingredient_sems_smoker[ing_id].acquire();
println!("[Fumador {:?}] Obtuve {:?}", me, ing);
}
}
println!("[Fumador {:?}] Fumando", me);
thread::sleep(Duration::from_secs(2));
agent_sem_smoker.release();
println!("[Fumador {:?}] Terminé", me);
})
})
.collect();
let _:Vec<()> = smokers.into_iter()
.flat_map(|x| x.join())
.collect();
agent.join().unwrap();
}
extern crate rand;
extern crate num_derive;
extern crate num_traits;
use std::sync::{Arc, Mutex, Condvar};
use std::thread;
use std::time::Duration;
use rand::{thread_rng};
use rand::seq::SliceRandom;
use num_derive::FromPrimitive;
use num_traits::FromPrimitive;
use std::thread::JoinHandle;
fn main() {
const N:usize = 3;
#[derive(Clone, Copy, Debug, FromPrimitive)]
enum Ingredients {
Tobacco = 0,
Paper,
Fire
}
let pair = Arc::new((Mutex::new([false, false, false]), Condvar::new()));
let pair_agent = pair.clone();
let agent = thread::spawn(move || loop {
let (lock, cvar) = &*pair_agent;
println!("[Agente] Esperando a que fumen");
let mut state = cvar.wait_while(lock.lock().unwrap(), |ings| {
let full_table = (*ings).iter().any(|i| *i);
println!("[Agente] Esperando a que fumen {:?} - {}", ings, full_table);
full_table
}).unwrap();
let mut ings = vec!(Ingredients::Tobacco, Ingredients::Paper, Ingredients::Fire);
ings.shuffle(&mut thread_rng());
let selected_ings = &ings[0..N-1];
for ing in selected_ings {
println!("[Agente] Pongo {:?}", ing);
state[*ing as usize] = true;
}
cvar.notify_all();
});
let smokers:Vec<JoinHandle<()>> = (0..N)
.map(|fumador_id| {
let pair_smoker = pair.clone();
let me = Ingredients::from_usize(fumador_id).unwrap();
thread::spawn(move || loop {
let (lock, cvar) = &*pair_smoker;
let mut _guard = cvar.wait_while(lock.lock().unwrap(), |ings| {
let my_turn = (0..N).all(|j| j == fumador_id || ings[j]);
println!("[Fumador {:?}] Chequeando {:?} - {}", me, ings, my_turn);
!my_turn
}).unwrap();
println!("[Fumador {:?}] Fumando", me);
thread::sleep(Duration::from_secs(2));
for ing in (*_guard).iter_mut() {
*ing = false;
}
println!("[Fumador {:?}] Terminé", me);
cvar.notify_all();
})
})
.collect();
let _:Vec<()> = smokers.into_iter()
.flat_map(|x| x.join())
.collect();
agent.join().unwrap();
}