When different threads only use unrelated objects and literally do not share anything they cannot have a race condition, right? Obviously.
Actually all threads share something: the address space. There is no guarantee that a memory location that was used by one thread isn't going to be allocated at some other time to another thread. This can be true of memory for dynamically allocated objects or even for automatic objects: there is no prescription that the memory space for the "stacks" (the local objects of functions) of multiple threads is pre-allocated (even lazily), disjoint and represented as the usual linear "stack"; it could be anything with stack (FILO) behavior. So the memory location used to store an automatic object can be reused later by another automatic object in another thread.
That in itself seems pretty innocuous and uninteresting as how room is made for automatic objects is only important when room is missing (very large automatic arrays or deep recursion).
What about synchronisation? Unrelated disjoint threads obviously cannot use any C++ synchronisation primitive to ensure correct synchronisation as by definition there is nothing (to) synchronize (on), so no happens before relation is going to be created between threads.
What if the implementation reuses the memory range of the stack of foo()
(including the location of i
) after destruction of local variables and exit of foo()
in thread 1 to store variables for bar()
in thread 2?
void foo() { // in thread 1
int i;
i = 1;
}
void bar() { // in thread 2
int i;
i = 2;
}
There is no happens before between i = 1
and i = 2
.
Would that cause a data race and undefined behavior?
In other words, do all multithread programs have a potential for having undefined behavior based on implementation choices the user has no control over, that are unforeseeable and with races he can't do anything about?