Rust is specifically designed to ensure that safe code can never trigger UB (barring compiler bugs, or bugs in unsafe code blocks). For that, protecting against races is necessary (at least when using LLVM as a backend, and when using the C++ memory model).
In practice rust also tries to guide you towards patterns that reduces the risk of other bugs. For example, using Result, Option (and enums in general) reduces the risk that you forget to handle error paths. It is also quite hard to get memory leaks unintentionally in Rust, since by default you work with various smart pointers.
In my experience typical multi-threaded C++ has a lot of threading bugs that tend to cause hard to reproduce bugs (I work in safety critical hard realtime robotics / machine control, where we have a lot of communicating threads). When I code Rust I can trust the language to prevent those classes of bugs, letting me focus on the actual hard domain specific problems, rather than language minutiae. Yes, TSAN helps in C++, but that is dynamic analysis so it has to actually catch the potential problem happening while running.
So I think that the multithreading approach in Rust is really good and what we want, not a hindrance. It is absolutely the right thing to do.
Now, the async story is another matter and I have conflicting opinions on how that is done in rust. I can't think of a significantly better design that would work on microcontrollers / no-std though. I'm not interested in anything that requires allocations or a runtime.