for some reasons that one of my mutex causes "deadlock" in the code.
in the code below inside the ability.perform function the hero_clone which is a mutex is deadlocked and after using lock().await method the program hangs forever.
(Im using tokio::sync::mutex because my functions are async)
use teloxide::dispatching::dialogue::{GetChatId, InMemStorage};
use teloxide::dispatching::{HandlerExt, UpdateFilterExt};
use teloxide::dptree::di::Injectable;
use teloxide::prelude::*;
use teloxide::types::*;
use tokio::sync::{Mutex, MutexGuard};
pub type Players = [Arc<Mutex<Player>>; 2];
pub type Heroes = [Arc<Mutex<Hero>>; 1];
pub impl Game {
pub fn get_current_turn(&mut self) -> Arc<Mutex<Player>> {
self.players[self.player_turn].clone()
}
}
pub struct Player {
pub id: UserId,
pub heroes: Heroes,
}
#[tokio::main]
async fn main() {
unsafe { GAMES.as_mut_ptr().write(HashMap::new()); }
pretty_env_logger::init();
log::info!("starting up");
let bot = Bot::env();
Dispatcher::builder(bot, dptree::entry()
.branch(Update::filter_message()
.enter_dialogue::<Message, InMemStorage<State>, State>()
.branch(dptree::case![State::PlayerTurn(id)].endpoint(player_turn))
.branch(dptree::case![State::Idle].endpoint(idle))
.branch(dptree::case![State::StartGame].endpoint(start_game)))
.branch(Update::filter_callback_query().endpoint(callback_query)))
.dependencies(dptree::deps![InMemStorage::<State>::new()]).enable_ctrlc_handler().build().dispatch().await;
}
type HandlerResult = Result<(), Box<dyn Error + Send + Sync>>;
async fn callback_query(bot: Bot, callback_query: CallbackQuery) -> HandlerResult {
let hero = usize::from_str(iter.next().unwrap_or("0")).unwrap_or(0);
let ability = usize::from_str(iter.next().unwrap_or("0")).unwrap_or(0);
let chat_id = callback_query.chat_id().unwrap();
let game_original = get_game(&chat_id);
let game = game_original.clone();
let mut game_mut = game.lock().await;
let heroes = ¤t_turn.heroes;
let mut hero = heroes.get(hero).unwrap();
let hero_clone = hero.clone();
let hero_mut = hero.lock().await;
let ability = hero_mut.abilities.get(ability).unwrap();
let opponent = game_mut.get_next_turn();
ability.perform(&bot, game.clone(), opponent, hero_clone).await;
game_mut.next_turn(&bot).await;
}
}
}
Ok(())
}
impl Ability {
async fn perform(&self, bot: &Bot, game: Arc<Mutex<Game>>, target: Arc<Mutex<Player>>, hero: Arc<Mutex<Hero>>) -> bool {
let mut hero_unlock = hero.lock().await; //Hangs here forever...
hero_unlock.damage(40);
hero_unlock.send_message(bot, &game.lock().await.id, "Take the khafang punchoo!".to_string()).await;
true
}
I don't really know if its a dumb question or not but forgive me since im new to rust :)
the perform function shouldn't hang on accessing the hero mutex init.
You are trying to lock hero
mutex twice.
// Here you lock mutex first time.
let hero_mut = hero.lock().await;
let ability = hero_mut.abilities.get(ability).unwrap();
let opponent = game_mut.get_next_turn();
// Here inside perform
// you try to lock it second time without unlocking first.
ability.perform(&bot, game.clone(), opponent, hero_clone).await;
Mutexes are often not recursive so they cannot be locked twice even in same thread.