The common solution to preventing deadlock in code is to make sure the sequence of locking occur in a common manner regardless of which thread is accessing the resources.
Another technique is transactional programming. This though is not very common as it usually involves specialized hardware (most of it currently only in research institutions).
Each resource keeps track of modifications from different threads. The first thread to commit changes to all resources (it is using) wins all other thread (using those resources) get rolled back to try again with the resources in the new committed state.
A simplistic starting point for reading on the subject is transactional memory.