Atomic operations, memory barriers, condition variables, thread/"virtual processor" scheduling are philosophically cleaner since they're what the specified hardware/OS concurrency model actually provides, and can implement all of locks, mutexes, structured concurrency, arbitrary queues, actors etc. etc.
I was implicitly including all those with mutexes in the last sentence, it might be easier to reason about each in isolation because you're an experienced programmer that can/want to reason about the details.
In practice you want to keep the sharp knives away from junior programmers in larger contexts, handling a few ones in a limited scope is ok but when you start to reason about larger systems, actors in concurrent contexts can be explained even to junior programmers in terms of conveyor belts of messages or a similar analogy.
I don't know if you heard the story of how C++ was used and a large part of the collapse of that project was due to C++, OO and/or threading issues and how Erlang was then used in a crash project to successfully write a replacement on the same HW.
Some people claim that functional programming and/or actor systems are inherently superior, I don't really agree on that assessment, it's more that the actor patterns were easily handled in a distributed system and when used by less seasoned programmers it was possible for them to create their parts in mostly "single-threaded" contexts + message passing without causing trouble by using lower level concurrency primitives.
Really, imagine 500+ mid-junior programmers banging away concurrent code on a larger project that needs to be shipped soon.
This is what I mean by philosophically cleaner.