简体   繁体   中英

C++ threads stack address range

Does the C++ standard provide a guarantee about the non-overlapping nature of thread stacks (as in started by an std::thread )? In particular is there a guarantee that threads will have have their own, exclusive, allocated range in the process's address space for the thread stack? Where is this described in the standard?

For example

std::uintptr_t foo() {
    auto integer = int{0};
    return std::bit_cast<std::uintptr_t>(&integer); 
    ... 
}

void bar(std::uint64_t id, std::atomic<std::uint64_t>& atomic) {
    while (atomic.load() != id) {}
    cout << foo() << endl;
    atomic.fetch_add(1);
}

int main() {
    auto atomic = std::atomic<std::uint64_t>{0};
    auto one = std::thread{[&]() { bar(0, atomic); }};
    auto two = std::thread{[&]() { bar(1, atomic); }};

    one.join();
    two.join();
}

Can this ever print the same value twice? It feels like the standard should be providing this guarantee somewhere. But not sure..

The C++ standard does not even require that function calls are implemented using a stack (or that threads have stack in this sense).

The current C++ draft says this about overlapping objects :

Two objects with overlapping lifetimes that are not bit-fields may have the same address if one is nested within the other, or if at least one is a subobject of zero size and they are of different types; otherwise, they have distinct addresses and occupy disjoint bytes of storage.

And in the (non-normative) footnote:

Under the “as-if” rule an implementation is allowed to store two objects at the same machine address or not store an object at all if the program cannot observe the difference ([ intro.execution ]).

In your example, I do not think the threads synchronize properly, as probably intended, so the lifetimes of the integer objects do not necessarily overlap, so both objects can be put at the same address.

If the code were fixed to synchronize properly and foo were manually inlined into bar , in such a way that the integer object still exists when its address is printed, then there would have to be two objects allocated at different addresses because the difference is observable.

However, none of this tells you whether stackful coroutines can be implemented in C++ without compiler help. Real-world compilers make assumptions about the execution environment that are not reflected in the C++ standard and are only implied by the ABI standards. Particularly relevant to stack-switching coroutines is the fact that the address of the thread descriptor and thread-local variables does not change while executing a function (because they can be expensive to compute and the compiler emits code to cache them in registers or on the stack).

This is what can happen:

  1. Coroutine runs on thread A and accesses errno .

  2. Coroutine is suspended from thread A.

  3. Coroutine resumes on thread B.

  4. Coroutine accesses errno again.

At this point, thread B will access the errno value of thread A, which might well be doing something completely different at this point with it.

This problem is avoid if a coroutine is only ever be resumed on the same thread on which it was suspended, which is very restrictive and probably not what most coroutine library authors have in mind. The worst part is that resuming on the wrong thread is likely appear to work, most of the time, because some widely-used thread-local variables (such as errno ) which are not quite thread-local do not immediately result in obviously buggy programs.

For all the Standard cares, implementations call new __StackFrameFoo when foo() needs a stack frame. Where those end, who knows.

The chief rule is that different objects have different addresses, and that includes object which "live on the stack". But the rule only applies to two objects which exist at the same time, and then only as far as the comparison is done with proper thread synchronization. And of course, comparing addresses does hinder the optimizer, which might need to assign an address for an object that could otherwise be optimized out.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM