tokio Mutex 在 Rust 中陷入死锁

问题描述 投票:0回答:1

由于某些原因,我的互斥锁之一导致代码中的“死锁”。

在下面的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 = &current_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 时挂起。

rust mutex
1个回答
0
投票

您正在尝试锁定

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;
© www.soinside.com 2019 - 2024. All rights reserved.