pseudomarvin
I guess the standard OOP way of solving this would be to create a GraphicsModel class and a descended MutexedGraphicsModel class with the second one containing the mutex.
This not "the standard OOP way". Actually, this is precisely the sort of "solution" that tends to create more problems than it solves. To be fair, it does preserve Liskov substitution, so the OO theorists will probably be okay with it.
I'm going to assume in what follows that you really need a mutex for some reason, but this may not be the case at all. A lightweight mutual exclusion mechanism (e.g. a spinlock) may be just as good. In fact, it's probably better in the case where you know locks won't be held for long, and at most two threads will want exclusive access to any object at any time.
If you really need a mutex (that is, if you really want a thread which is trying to acquire exclusive access to sleep if it can't get it), then one traditional way of doing this is called a "lock table". Conceptually, a lock table is a dictionary (e.g. hash table) which maps objects to locks. I think this originally came from databases, where you may want to lock individual rows of a database table.
One "pure OOP" way of doing it would be to make GraphicsModel purely abstract (i.e. what Java programmers would call an Interface), and then make two concrete classes (one thread-safe, one not) and share implementation by sharing a member. An even more OO solution is to use a
decorator pattern, which adheres strictly to the single responsibility principle.
One "Modern C++" way of doing it would be to use
policy-based design. You'd make your GraphicsModel class templated on the thread safety policy, and plug in which one you need. The other, if you're really up-to-date, is to use a
generic monitor wrapper. What could be simpler, right?
The "software engineer in a hurry" solution would be to just use the mutex all the time. On modern platforms, mutexes are cheap enough for many purposes if there is no contention (and usually much cheaper than whatever they're protecting), and it protects the code from being misused in the future by someone who doesn't fully understand the code. That someone may well be you six months from now.
The "data oriented" solution is to look at the data and see what it's trying to tell you. Why are these GraphicsModels being rendered and mutated in different threads simultaneously in the first place? Did the data actually suggest that as a solution?