We had multi CPU stuff in the 90s. C/C++ was dead set on ignoring it for a long time. Every OS had its own way of handling it and all with subtle weird bits that did not act like other OS's. You could not even trust the stdlib or crt to get it right with their globals that could change underneath you.
So it was left to the developer. It is much better now but for so long the problem was ignored and now we have decades of 'not sure if I can touch that code'. Also by default C/C++ are fairly open about sharing memory. So it is very easy create race conditions on memory. It would be nice if the base language had a concept of 'locked to a thread' or 'i want to share this with other threads' then the compiler can flag where I have wandered into the weeds for a class so we could catch the race conditions at compile time, at least some sort of warning.
Sharing semantics were awful for a long time. stdlib has done some very good things to help clean that up but it is still very easy to share between threads and cause yourself a headache.
C++ itself doesn't have the owning mutex, but there is one in Boost for example.
The problem with an owning mutex in such a language is that you can (on purpose or by mistake) keep accessing the thing it owned after you've released the protecting mutex. Rust's Mutex<T> owns the T but it has the behaviour you want where if you tried to keep the access to T but give back the mutex that doesn't compile. "I tried to unlock the mutex but I still need it, d'oh".
And the same problem applies broadly, you should not share write access to things without an ordering guarantee, but it's hard to ensure that guarantee is followed in C++.
Exactly. This stuff has been known about for a long time. It was just kind of ignored and you kinda hoped your library might have something to deal with it (boost, win32, pthread, etc). Then each one acted differently on different platforms or with each other. Some of the std lib is starting to have things we need. But now I have to deal with things in the crt and stdlib that actively break multi threading. Mutexes, semaphores, flags, pulsing, etc is not exactly new patterns. Real mess and you have to understand it too deeply for it to be meaningful to more people. It is why things like promise/async/await are very popular with javascript and their libraries. As it looks like multithreaded programming with a decently clear interface as to what it is going on.
CPU design makes it inherently hard. C or C++ is just a thin layer above it making no tradeoffs. If you can live with the tradeoff then Rust land or VM-language land is more appropriate.
In theory none but in practice the codebase ends up littered with hidden shared state mostly disguised through one or another shared pointer implementation. And this happens because that's what the Rust compiler is pessimistically enforcing upon you by default.
For heavy workloads, this approach doesn't scale particularly very well.
It sounds to me as though what you're saying is that when you write Rust programs which don't scale very well they don't scale very well, whereas when you write C++ programs you don't do that, I suggest learning not to do it in Rust either.
Easier to be said than done since that's one of the core tradeoffs of the Rust language. Language is forcing these semantics upon you and while it is possible to get around it with unsafe blocks it turns out to be much more difficult in the practice. So, by default Rust code will almost certainly in majority of cases going to be designed around shared ownership.
If you actually have shared ownership but in C++ you're getting away with pretending you don't, chances are that'll bite you really hard. Maybe it's already biting and you didn't notice, so Rust actually do you a massive favour.
If there is no shared ownership then inventing it so as to make your Rust slower is just a problem with you, not with Rust.
No. For 98% of the multi-core sensitive code I don't have nor I need shared ownership. While C++ doesn't force you into such semantics but provides you with the ability to do so, the Rust semantics and compiler pesimisstically do. I am going to stop here since I'm repeating myself and you're blatantly going over my points.