From a practical perspective, you’re over thinking this. The most common behavior is to wrap the shared resource (regardless of type) in a mutex.
The standard way to solve the problem of remembering to access it properly is to wrap it in a class with locking accessors as you mentioned.
Either is fine and works for 99% of applications.