mutual exclusion and the critical-section problem
Imagine a single bathroom shared by a whole office, with no lock on the door. If two people wander in at the same moment, you get an embarrassing collision. The polite fix is a lock: only one person inside at a time, everyone else waits their turn. Mutual exclusion is exactly that rule applied to running code — for some short stretch of work, only one thread may be 'inside' at once.
The stretch of code that must not be entered by two threads at the same time is called a critical section. It is usually a few lines that touch shared data: read a counter, add one, write it back. If two threads run those lines interleaved, they can both read the old value and both write the same new value, so one increment is silently lost. The critical-section problem is the puzzle of building a gatekeeper so that at most one thread is in the critical section at any instant (mutual exclusion), while also making sure threads do not block each other forever (progress) and no thread waits indefinitely (bounded waiting). Mutual exclusion is the property you want; a mutex, a spinlock, or a semaphore is a tool that provides it.
It matters because the moment two threads share mutable memory, the hardware gives you no built-in turn-taking — the CPU is free to interleave their instructions in any order. Mutual exclusion is the discipline that turns 'whoever gets there first wins, sometimes corrupting data' into 'one at a time, correctly'. Nearly every primitive in this field exists to provide mutual exclusion or to coordinate around it. Note that mutual exclusion only protects the code regions you actually wrap — data touched outside every critical section is still unprotected.
Two threads each run count = count + 1 a million times. Without mutual exclusion the final count is often far below two million, because increments interleave and overwrite each other; wrapping the increment in a lock restores the correct result.
The critical section is the read-modify-write of count; mutual exclusion lets only one thread run it at a time.
Mutual exclusion is a property, not a piece of code: you achieve it by agreeing that every access to the shared data goes through the same lock. One thread that touches the data without taking the lock breaks the guarantee for everyone.