22

私は C++ でスレッド化するのが初めてで、スレッド間でメモリがどのように共有されているか、共有されていないかを明確に把握しようとしています。std::threadC++11で使用しています。他のSOの質問で読んだことから、スタックメモリは1つのスレッドのみが所有し、ヒープメモリはスレッド間で共有されます。したがって、スタックとヒープについて理解していると思うことから、次のことが当てはまるはずです。

#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);
}

ラムダ構文は私にとって非常に新しいものです。しかし、うまくいけば、私がやろうとしていることは首尾一貫しています。これは期待どおりに機能しますか? そうでない場合、私は何を誤解していますか?

4

2 に答える 2

29

記憶は記憶です。C ++のオブジェクトは、メモリ内のある場所を占めます。その場所は、スタックまたはヒープ上にあるか、静的に割り当てられている可能性があります。オブジェクトがどこにあるかは関係ありません。オブジェクトへの参照またはポインタを持つスレッドは、オブジェクトにアクセスできます。2つのスレッドにオブジェクトへの参照またはポインターがある場合、両方のスレッドがそれにアクセスできます。

std::threadプログラムでは、指定したラムダ式を実行するワーカースレッドを(を作成して)作成します。両方stackObjheapObj参照によって([&]キャプチャのデフォルトを使用して)キャプチャするため、そのラムダにはこれらのオブジェクトの両方への参照があります。

heapObjこれらのオブジェクトは両方ともメインスレッドのスタックにあります(メインスレッドのスタックにあり、ヒープにある動的に割り当てられたオブジェクトを指すポインター型オブジェクトであることに注意してください)。これらのオブジェクトのコピーは作成されません。むしろ、ラムダ式にはオブジェクトへの参照があります。直接変更し、間接的stackObjにポイントされたオブジェクトを変更します。heapObj

メインスレッドがワーカースレッドと結合した後、両方heapObj->xstackObj.x値は。になり1ます。


値キャプチャのデフォルト([=])を使用した場合、ラムダ式はとの両方をコピーします。ラムダ式の式はコピーをインクリメントし、宣言したは変更されません。 stackObjheapObjstackObj.x++stackObjmain()

by値をキャプチャするとheapObj、ポインタ自体のみがコピーされるため、ポインタのコピーが使用されている間も、動的に割り当てられた同じオブジェクトを指します。式heapObj->x++はそのポインターを逆参照し、をObj介して作成したものを生成しnew Obj()、その値をインクリメントします。次に、その最後に増分されているmain()ことを確認しheapObj->xます。

(値によってキャプチャされたオブジェクトを変更するには、ラムダ式を宣言する必要があることに注意してくださいmutable。)

于 2012-07-05T20:44:11.787 に答える
1

私はジェームズ・マクネリスに同意heapObj->xstackObj.xます1.

さらに、このコードは、スレッドを生成した直後にのみ機能します。joinスレッドを開始し、実行中にさらに作業を行った場合、例外によってスタックが巻き戻され、新しいスレッドが突然stackObj無効になる可能性があります。そのため、たとえ技術的に可能であっても、スレッド間でスタック メモリを共有することはお勧めできません。

于 2012-07-05T20:47:48.960 に答える