If SOLID principals apply in spades to regular code, then there's a power law for concurrent code.
When Simon Peyton Jones was working at Microsoft Research on Software Transactional Memory, he prefaced practically every video/interview with this uncomfortable fact. Given the lack of traction, I can only assume that some of the corner cases of STM proved to be intractable, and my read on the domain is that borrow semantics are trying to arrive at a similar place by different avenues. I'm very interested to see 1) how far borrow semantics get, in the same way that type inference simplifies generics, and 2) what someone tries next, particularly if it involves synthesizing elements from different schools.
I do a lot of concurrency stuff, and my go-to is one form or another of message passing. It isn't a miracle cure, but it turns the exponentially complicated issues with lock-based systems into polynomial ones, and that's at least something you have a prayer of managing. They compose better. I'm not sure I'd say they compose well, and someone may yet find an even better model, but they compose better.
(STM doesn't seem to be that model. As the transactions inevitably get larger over time they start getting complicated.)
At least for these two classes of categories, mutex usage at Google is broadly paired with compiler-enforced annotations to enforce that _all_ accesses to mutex-guarded member variables are done while holding the appropriate mutex.
https://abseil.io/docs/cpp/guides/synchronization#thread-ann...
(While yes, it can also help with deadlock avoidance as well, that tends to be trickier to enforce across the board, especially if the mutexes in question belong to different objects. There's separate deadlock detection baked into Abseil that's used primarily in non-production builds.)