This exposes an important, and to me non-obvious, property of concurrency. That it's not the locking that's really hard, it's how to be sure that every piece of related data is included in the lock (or STM).
I think that according to standard terminology, syncing accesses to mutable data does prevent all data races - but not all race conditions: http://blog.regehr.org/archives/490 (Race Conditions vs Data Races)
The nice thing about eliminating queue-like interfaces - and locks, STM, message passing, lock-free containers etc. are actually a form of a queue-like interface - is that it eliminates all race conditions which aren't data races. Then you can have automated debugging tools find said data races.
Unfortunately, this doesn't work with event handling systems, because they're often required to have queue semantics to resolve inevitable conflicts between requests.
Sure; a parallel for loop with each task processing a, a, ... a[N] has no data races but if task 0 modifies a and reads a, task 1 modifies a and reads a, etc. then this loop is full of data races without there being anything queue-like (that is, you never say "I'll do this thing here unless someone beats me to it in which case I will let them finish first.")