It's great that you're curious. A simplified explanation follows with a few links to delve into:
All of the programs running in parallel is actually an illusion that is created by the OS.
Even if we have a uniprocessor system, the OS can still achieve the same thing.
For multiple programs running on the system, OS creates separate processes.
There are many approaches for concurrency, with different tradeoffs. We have threads with shared mutable state (e.g., SRC-style threading). We have coroutines (like Go). We have actor models with independent processes communicating via message passing (like Erlang or E).
I would put CSP on a different level. It's not the same sort of thing. The form of ...
When using semaphores or locks, you don't do anything else than acquiring the semaphore (resp. the lock), and then do what you want. For example, if you want to use a lock, then you typically have two threads
# thread 1
# here is all the work for thread 1
and the other thread is completely identical:
# thread 2
These are two distinct phenomena. Contention refers to the fact that when thread $A$ has accessed a resource $B$ needs to wait until $A$ frees it.
Race refers to the fact when both threads $A$ and $B$ want to secure access to a resource. The fastest will secure it and thus lead to contention.
Practically speaking, the C++ threading (memory) model is directly inspired by the Java Memory Model, and C followed. Hans Böhm was closely involved with the process and has a great resource list. (*)
You'll quickly note that your dates are pretty optimistic - this memory model did not exist in 1985 when the first C++ implementations were created. There's ...