由于某些原因,我的互斥锁之一导致代码中的“死锁”。
在下面的capability.perform函数中的代码中,作为互斥锁的hero_clone是死锁的,并且在使用lock().await方法之后程序将永远挂起。
(我使用 tokio::sync::mutex 因为我的函数是异步的)
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
}
我真的不知道这是否是一个愚蠢的问题,但请原谅我,因为我是 Rust 新手:)
执行函数不应在访问英雄互斥体 init 时挂起。
您正在尝试锁定
hero
互斥体两次。
// 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;