【发布时间】:2019-07-11 08:50:47
【问题描述】:
C++ 标准是否提供关于线程堆栈的非重叠性质的保证(如由std::thread 启动的那样)?特别是是否可以保证线程在线程堆栈的进程地址空间中有自己的、独占的、分配的范围?这在标准中在哪里描述?
例如
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();
}
这可以打印两次相同的值吗?感觉标准应该在某个地方提供这种保证。但不确定..
【问题讨论】:
-
这是一个有趣的问题。我总是用常识来判断堆栈永远不会重叠。想象一下,如果它们可以重叠——你怎么能期望程序的行为是明确定义的?
-
@paddy 我同意,但很好奇你的意思,如果你有一些情况会导致程序爆炸。你有一个例子吗?一旦你将协程引入混合中,这些事情就会开始变得奇怪。突然间,如果 foo() 是一个协程,这变得可能,因为协程框架是堆分配的
-
堆和栈完全不同。即使
foo是一个lambda 或其他什么,实际上调用foo从一个线程将使用该线程的堆栈。堆栈的目的是提供有保证的非重叠存储,其中进程存储执行所需的临时数据,包括函数调用的返回地址。如果两个线程的堆栈指针可能发生冲突或交叉,那么您将处于非常艰难的时期。 -
作为 pthreads 的旁白,我过去必须在入口处设置堆栈大小。例如,请参阅unix.stackexchange.com/questions/127602/…。
-
当然,如果定义明确,您的意思是“将打印一个值”。但是 what 将打印的值根本没有定义。我认为,如果
foo是一个使用co_return返回其值的协程,则没有什么可以阻止多个线程中对它的两个非重叠调用返回相同的值。事实上,即使没有协程,您的示例也不要求两个线程同时存在。可以想象一个线程可以在另一个线程创建之前完成,因此第二个线程可以继承与第一个线程相同的堆栈地址范围。
标签: c++ multithreading stack pthreads language-lawyer