If you're calling back into user code, you need to reestablish invariants first.
As for threading, C++ distinguishes mutating from non mutating (const) methods. Usually, any number of threads can call const methods simultaneously, but only one thread can have access if mutating methods are called. This may require external synchronisation.
The optimizer is often capable of inferring when invariants are maintained. One controversy is whether it should be permitted to use contracted invariants as axiomatic.
As for threading, C++ distinguishes mutating from non mutating (const) methods. Usually, any number of threads can call const methods simultaneously, but only one thread can have access if mutating methods are called. This may require external synchronisation.
The optimizer is often capable of inferring when invariants are maintained. One controversy is whether it should be permitted to use contracted invariants as axiomatic.