It's not fundamentally different from having bound checks for array indices. You can either do that pretty easily at runtime or use a simple type system to do it at compile time (e.g., Boyapati's [1] or Flanagan's [2] work). It's been done, e.g. for Cyclone [3]. This is decades old stuff, not rocket science. Honestly, Monitors had the basic idea right in the 1970s, except as Per Brinch Hansen lamented [4], language designers keep screwing it up.
[1] http://www.pmg.lcs.mit.edu/~chandra/publications/oopsla02.pd...
[2] http://users.soe.ucsc.edu/~cormac/papers/esop99.pdf
[3] https://homes.cs.washington.edu/~djg/papers/cycthreads.pdf
Also, you can use shared memory in Rust. If you do, the type system ensures there can be no data races: either the data is immutable or you must take the lock before you mutate the data.
In Rust, this style is enforced by the language. In C++11 you can enforce it by the convention of using std::unique_ptr and passing those between threads via a shared data structure like a blocking queue.