我是新的C ++穿线,我试图获取有关内存是如何共享/线程之间不共享的清晰画面。 我使用std::thread
与C ++ 11。 从我读过的其他SO问题, 堆栈存储器仅由一个线程拥有和堆内存线程之间共享。 所以从我想我了解了堆栈主场迎战堆,下面应该是真实的:
#include <thread>
using namespace std;
class Obj {
public:
int x;
Obj(){x = 0;}
};
int main() {
Obj stackObj;
Obj *heapObj = new Obj();
thread t([&]{
stackObj.x++;
heapObj->x++;
});
t.join();
assert(heapObj->x == 1);
assert(stackObj.x == 0);
}
原谅我,如果我搞砸了一堆东西,lambda语法是非常新的我。 但希望是我想要做的是一致的。 这会执行如我所料? 如果不是,我是什么误会?
内存是内存。 在C ++的对象在存储器中占用一些位置; 该位置可以是在叠层或在堆上,或它可能已被静态分配。 不要紧,在对象所在:具有引用或指向对象可以访问该对象的任何线索。 如果两个线程有一个参考或指针的对象,则这两个线程可以访问它。
在你的程序中,创建一个工作线程(通过构造std::thread
)执行lambda表达式你提供。 因为你同时捕捉stackObj
和heapObj
引用(使用[&]
捕获默认值),该拉姆达有这两个对象的引用。
这些对象都位于主线程的栈上(注意heapObj
是位于主线程的栈和点上到位于在堆上一个动态分配的对象的指针型对象)。 这些对象的任何副本制成; 相反,你的lambda表达式具有对对象的引用。 它修改stackObj
直接并修改目的是通过指向heapObj
间接。
之后,主线程加入与工作线程,既heapObj->x
和stackObj.x
具有值1
。
如果您已经使用了价值获取默认( [=]
您的lambda表达式会复制这两个stackObj
和heapObj
。 表达stackObj.x++
在lambda表达式将增加复制和stackObj
您在声明main()
将保持不变。
如果您捕捉heapObj
的价值,只有指针本身被复制,因此使用指针的一个拷贝,同时,它仍然指向同一个动态分配的对象。 表达heapObj->x++
将解引用该指针,得到Obj
你通过创建new Obj()
和增加它的价值。 然后你会看到在年底main()
是heapObj->x
已递增。
(注意,为了修改由值捕获的对象,λ表达式必须被声明mutable
。)
我与詹姆斯McNellis同意heapObj->x
和stackObj.x
将是1
。
此外,因为你这个代码只能 join
产卵线程之后。 如果启动线程,然后做更多的工作,而它运行时,一个异常可能展开堆栈,突然新线程的stackObj
无效。 这就是为什么线程之间共享堆栈存储器是即使它在技术上可能是一个坏主意。