Update: In your case, when each class has its own mutex, and the problem is only in the order of calls, I would not recommend to call someone else's code under blocking. Just because this code has the full right to lock some other mutex. Calling someone else's code under a locked mutex is almost always a deadlock danger.
Try reorganizing the code to look like this:
void obj1.method1() { { std::lock_guard g1(mutex1); // ΡΠ°Π±ΠΎΡΠ°Π΅ΠΌ Ρ Π΄Π°Π½Π½ΡΠΌΠΈ/Π·Π°ΠΏΠΎΠΌΠΈΠ½Π°Π΅ΠΌ ΠΈΡ
} // ΡΠΎΠ»ΡΠΊΠΎ Π·Π΄Π΅ΡΡ ΠΌΡ ΠΈΠΌΠ΅Π΅ΠΌ ΠΏΡΠ°Π²ΠΎ Π²ΡΠ·Π²Π°ΡΡ ΠΎΠ±ΡΠ΅ΠΊΡ, ΠΊΠΎΡΠΎΡΡΠΉ ΠΌΡ Π½Π΅ ΠΊΠΎΠ½ΡΡΠΎΠ»ΠΈΡΡΠ΅ΠΌ obj2.method2(); }
You cannot get out of this situation. Classes using shared mutexes must cooperate.
Often the problem is solved in this way: the mutexes are renumbered, and if the code wants to take several mutexes, it must take them in ascending order of numbers.
On the other hand, you can reduce the blocking granularity, and use one mutex instead of both (if it is permissible within your task).
Also, you can try to avoid the double mutex problem by dividing the work with blocked objects into parts / entities: first lock one mutex and retrieve the necessary data, then release this mutex and lock the other using local data when working with the second object.
Another popular approach is to get rid of shared data, if possible, and work as much as possible with local data.
Summary: there is no common solution. Get out.