C++ 线程之间的内存共享
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11352249/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Memory sharing between C++ threads
提问by Michael Dorst
I'm new to threading in C++, and I'm trying to get a clear picture about how memory is shared/not shared between threads. I'm using std::thread
with C++11.
From what I've read on other SO questions, stackmemory is owned by only one thread and heapmemory is shared between threads. So from what I think I understand about the stack vs. the heap, the following should be true:
我是 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);
}
forgive me if I screwed up a bunch of stuff, lambda syntax is very new to me. But hopefully what I'm trying to do is coherent. Would this perform as I expect? And if not, what am I misunderstanding?
如果我搞砸了一堆东西,请原谅我,lambda 语法对我来说很新。但希望我想做的事情是连贯的。这会按我的预期执行吗?如果不是,我有什么误解?
回答by James McNellis
Memory is memory. An object in C++ occupies some location in memory; that location may be on a stack or on the heap, or it may have been statically allocated. It doesn't matter where the object is located: any thread that has a reference or pointer to the object may access the object. If two threads have a reference or a pointer to the object, then both threads may access it.
记忆就是记忆。C++ 中的对象在内存中占有一定的位置;该位置可能在堆栈上或堆上,也可能是静态分配的。对象位于何处无关紧要:任何具有对象引用或指针的线程都可以访问该对象。如果两个线程都有一个对象的引用或指针,那么两个线程都可以访问它。
In your program, you create a worker thread (by constructing a std::thread
) that executes the lambda expression you provide it. Because you capture both stackObj
and heapObj
by reference (using the [&]
capture default), that lambda has references to both of those objects.
在您的程序中,您创建了一个工作线程(通过构造 a std::thread
)来执行您提供的 lambda 表达式。因为您同时捕获stackObj
和heapObj
通过引用(使用[&]
捕获默认值),所以该 lambda 对这两个对象都有引用。
Those objects are both located on the main thread's stack (note that heapObj
is a pointer-type object that is located on the main thread's stack and points to a dynamically allocated object that is located on the heap). No copies of these objects are made; rather, your lambda expression has references to the objects. It modifies the stackObj
directly and modifies the object pointed to by heapObj
indirectly.
这些对象都位于主线程的堆栈上(请注意,这heapObj
是一个指针类型的对象,位于主线程的堆栈上并指向位于堆上的动态分配对象)。没有复制这些对象;相反,您的 lambda 表达式具有对对象的引用。它stackObj
直接修改 ,heapObj
间接修改指向的对象。
After the main thread joins with the worker thread, both heapObj->x
and stackObj.x
have a value of 1
.
主线程加入工作线程后,heapObj->x
和stackObj.x
的值都为1
。
If you had used the value capture default ([=]
), your lambda expression would have copiedboth stackObj
and heapObj
. The expression stackObj.x++
in the lambda expression would increment the copy, and the stackObj
that you declare in main()
would be left unchanged.
如果您已经使用了价值获取默认的([=]
),您的lambda表达式会复制都stackObj
和heapObj
。stackObj.x++
lambda表达式中的表达式将增加copy,而stackObj
您声明的main()
将保持不变。
If you capture the heapObj
by value, only the pointer itself is copied, so while a copy of the pointer is used, it still points to the same dynamically allocated object. The expression heapObj->x++
would dereference that pointer, yielding the Obj
you created via new Obj()
, and increment its value. You would then observe at the end of main()
that heapObj->x
has been incremented.
如果捕获heapObj
by 值,则只会复制指针本身,因此在使用指针的副本时,它仍指向同一个动态分配的对象。该表达式heapObj->x++
将取消引用该指针,产生Obj
您通过创建的new Obj()
,并增加其值。然后你会在最后观察main()
到heapObj->x
它已经增加了。
(Note that in order to modify an object captured by value, the lambda expression must be declared mutable
.)
(请注意,为了修改按值捕获的对象,必须声明 lambda 表达式mutable
。)
回答by japreiss
I agree with James McNellis that heapObj->x
and stackObj.x
will be 1
.
我同意 James McNellis 的观点,heapObj->x
并且stackObj.x
会1
。
Furthermore, this code onlyworks because you join
immediately after spawning the thread. If you started the thread and then did more work while it runs, an exception could unwind the stack and suddenly the new thread's stackObj
is invalid. That is why sharing stack memory between threads is a bad idea even if it's technically possible.
此外,此代码仅join
在您生成线程后立即起作用。如果您启动该线程,然后在它运行时做了更多工作,则异常可能会展开堆栈,并且突然间新线程的stackObj
无效。这就是为什么在线程之间共享堆栈内存是一个坏主意,即使它在技术上是可行的。