2016-08-15 2 views
1

スレッドの共有メモリは分かっていますが、独自のスタックを持っています。 したがって、スタックで割り当てられたオブジェクトを別のスレッドで実行される関数に(多態的な理由で)ポインタを介して渡すと、これは安全になるか、未定義の動作になります。たとえば、このコード:foo_objectがスコープ外になった後、foo_objectへのポインタが無効になりますが、スレッドが無効なメモリにアクセスする可能性があるため他のスレッドで実行される関数へのポインタによってスタック割り当てオブジェクトを渡す

struct Foo{ 
    int counter{0}; 
} 

void bar(Foo * obj){ 
    obj->counter++; 
} 
int main(){ 
    { 
     Foo foo_object; 
     std::thread t(bar, &foo_object); 
     t.detach(); 
    } 
    //do more stuff 
} 

は、この安全ではありませんか? 私は強い感情を持っています、これは未定義の行動を生み出しますが、私は100%確信していません。

+0

100%確実ではない理由は何ですか? –

+0

「安全な」とは「正しい」という意味ですか? –

+0

はい私は正しかったという意味で安全であることを意味していますが、これは明らかでない場合はごめんなさい – Exagon

答えて

5

これは安全ではありません。あなたは

{ 
    Foo foo_object(); 
    std::thread t(bar, &foo_object); 
    t.detach(); 
} 

foo_object}を取得したらスコープの外に行くと、あなたは切り離されたスレッド中のダングリングポインタで残されます。スレッドが実際に起動するかどうかわからないので、スタックベースのローカルオブジェクトは、使用するときにすでに破棄されている可能性があります。


Foo foo_object();は、関数宣言ではなく、ローカル変数であることに注意してください。変数を持つにはFoo foo_object;が必要です。

+0

私はあなたに感謝しました。 – Exagon

0

foo_objectはスコープの終わりに破棄されるため、別個のスレッドへのポインタを渡すことは安全ではありません。 foo_objectが破棄された後、別のスレッドがダングリングポインタを参照解除しようとすると、未定義の動作が発生します。

1

FooがアクセスするまでにFooが破壊されるため、現在のコードは安全ではありません。

あなたがC++ 17を持っている希望の場合、私が書くことをお勧め:あなたが唯一++、11 C持っているように、私は次のことを書いて検討するものの

std::thread t([foo_object = Foo{}]{ bar(&foo_object); }); 

を:

auto foo_object = std::make_shared<Foo>(); 
std::thread t([foo_object]{ bar(foo_object.get()); }); 

それ主に動作しますが、shared_ptrを使用していない可能性があります。 もう1つの方法は次のとおりです。

std::thread t([]{ Foo foo_object; bar(&foo_object); }); 
+0

C++ 17の機能は何ですか?新しいスレッドスタックにfoo_objectという新しいオブジェクトが作成されますか? – Exagon

+1

これはLambdaオブジェクトの内部に作成されます。 – JVApen

関連する問題