0

I'm trying to create some kind of history manager system. Which would be able to redo and undo actions. I'm locking my road_manager in my main loop. So that lock never expires. But then when I try to use my road_manager again I have to lock it, which would result in a deadlock. How can I avoid this? I'm using lazy_static so I can use my managers globally.

main.rs, where I define my manager variables:

lazy_static! {
    pub static ref HISTORY_MANAGER: Mutex<managers::history::HistoryManager> =
        Mutex::new(managers::history::HistoryManager::new());
    pub static ref ROAD_MANAGER: RwLock<managers::road::RoadManager> =
        RwLock::new(managers::road::RoadManager::new());
    // There are and will be more managers, but they're unrelated
}

/// Returns the history manager
pub fn get_history_manager() -> &'static Mutex<managers::history::HistoryManager> {
    &HISTORY_MANAGER
}

/// Returns the road manager
pub fn get_road_manager() -> &'static RwLock<managers::road::RoadManager> {
    &ROAD_MANAGER
}

window.rs, my main loop where I lock road_manager:

let mut road_manager = crate::get_road_manager().write().unwrap();

// road_manager gets used every frame, for things like writing and reading from the cache.

get_history_manager().lock().unwrap().undo(); // gets called whenever the undo button is pressed

Then, in my history manager—upon the undo function I'll have to use my road_manager again. Which will not work since that'll result in a deadlock.

crate::get_road_manager().write().unwrap().destroy(road._id.unwrap()); // thread 'main' panicked at 'rwlock write lock would result in deadlock'

Full source code can be found here, for if you need more context.

Tetie
  • 365
  • 1
  • 14
  • Reducing the time the mutex is locked will help avoid deadlocks so *"I'm locking my road_manager in my main loop. So that lock never expires."* is probably a bad idea. – kmdreko Apr 04 '23 at 19:26
  • Yeah that's why I'm looking for an alternative. I want my manager to be used in a variety of different scripts and this is the only solution I could find. – Tetie Apr 04 '23 at 19:34
  • Your other options are to pass the `RoadManager` around instead of using the global variable (so you use the already locked access to it) but it seems you're using globals to specifically avoid that (don't) or use a reentrant mutex (which allow you to lock multiple times) but that wouldn't grant mutable access to the inner value. – kmdreko Apr 04 '23 at 19:52
  • 1
    I took a look at your main loop, and I don't see a reason why you need to hold the lock the entire time. Simply lock it when you need it. – kmdreko Apr 04 '23 at 20:04
  • Why not? Where would I lock it and where wouldn't I? – Tetie Apr 05 '23 at 05:03
  • I just tried using `drop()` before my undo function and then assigning it again after but I'm still having exactly the same issue. – Tetie Apr 05 '23 at 13:30

0 Answers0