简体   繁体   English

C ++线程之间的内存共享

[英]Memory sharing between C++ threads

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. 我是C ++新线程的新手,我试图清楚地了解线程之间如何共享/不共享内存。 I'm using std::thread with C++11. 我正在使用std::thread和C ++ 11。 From what I've read on other SO questions, stack memory is owned by only one thread and heap memory is shared between threads. 从我在其他SO问题上看到的, 堆栈内存只由一个线程拥有, 内存在线程之间共享。 So from what I think I understand about the stack vs. the heap, the following should be true: 所以从我认为我对堆栈与堆的理解,以下内容应该是正确的:

#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. 原谅我,如果我搞砸了一堆东西,lambda语法对我来说是非常新的。 But hopefully what I'm trying to do is coherent. 但希望我正在努力做的是连贯的。 Would this perform as I expect? 这会像我期望的那样表现吗? And if not, what am I misunderstanding? 如果没有,我有什么误解?

Memory is memory. 记忆是记忆。 An object in C++ occupies some location in memory; C ++中的对象占用内存中的某个位置; 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. 如果两个线程有​​一个引用或指向该对象的指针,则两个线程都可以访问它。

In your program, you create a worker thread (by constructing a std::thread ) that executes the lambda expression you provide it. 在您的程序中,您创建一个工作线程(通过构造一个std::thread )来执行您提供的lambda表达式。 Because you capture both stackObj and heapObj by reference (using the [&] capture default), that lambda has references to both of those objects. 因为您通过引用捕获stackObjheapObj (使用[&]捕获默认值),所以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). 这些对象都位于主线程的堆栈上(请注意, heapObj是一个指针类型对象,位于主线程的堆栈上,指向位于堆上的动态分配对象)。 No copies of these objects are made; 没有制作这些物品的副本; rather, your lambda expression has references to the objects. 相反,您的lambda表达式具有对象的引用。 It modifies the stackObj directly and modifies the object pointed to by heapObj indirectly. 它直接修改heapObj间接修改stackObj指向的对象。

After the main thread joins with the worker thread, both heapObj->x and stackObj.x have a value of 1 . 主线程与工作线程连接后, heapObj->xstackObj.x的值均为1


If you had used the value capture default ( [=] ), your lambda expression would have copied both stackObj and heapObj . 如果您使用了值捕获默认值( [=] ),则lambda表达式将复制 stackObjheapObj 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.x++将增加副本 ,并且在main()声明的stackObj将保持不变。

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. 如果按值捕获heapObj ,则只复制指针本身,因此在使用指针的副本时,它仍然指向同一个动态分配的对象。 The expression heapObj->x++ would dereference that pointer, yielding the Obj you created via new Obj() , and increment its value. 表达heapObj->x++将解引用该指针,得到Obj你通过创建new Obj()和增加它的价值。 You would then observe at the end of main() that heapObj->x has been incremented. 然后,您将在main()的末尾观察到heapObj->x已递增。

(Note that in order to modify an object captured by value, the lambda expression must be declared mutable .) (注意,为了修改由value捕获的对象,必须将lambda表达式声明为mutable 。)

I agree with James McNellis that heapObj->x and stackObj.x will be 1 . 我同意James McNellis的观点,即heapObj->xstackObj.x将为1

Furthermore, this code only works because you join immediately after spawning the thread. 此外,此代码起作用,因为您在生成线程后立即join 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. 如果你启动了线程,然后在运行时做了更多的工作,一个异常就可以展开堆栈,突然新线程的stackObj无效。 That is why sharing stack memory between threads is a bad idea even if it's technically possible. 这就是为什么在线程之间共享堆栈内存是一个坏主意,即使它在技术上是可行的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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