2016-05-07 6 views
3

私は次のコードブロックを持っています。私が期待したのは、ラムダキャプチャリスト内のiが値渡しされ、iが出力されるはずです。ループ内のこのラムダ関数がなぜパラメータを値で取得しなかったのですか?

しかし、実際の結果は19 is completedという出力20行です。

この行をに変更しようとしましたが、std::thread t([func](){に出力すると、異なるiの値が出力される可能性があります。

私の質問は、std::thread t([&func](){std::thread t([func](){がiの異なる出力値を導くのはなぜですか?

void DoSomething(std::function<void()> func) 
{ 
    std::thread t([&func](){ 
     //do something 
     sleep(1); 
     if (func) 
      func(); 
    }); 
    t.detach(); 
} 

int main(int argc, const char * argv[]) { 
    std::mutex mtx; 
    for (int i = 1 ; i < 20; i ++) { 
     DoSomething([i, &mtx](){ 
      std::unique_lock<std::mutex> lock(mtx); 
      std::cout << i << " is completed" << std::endl;; 
     }); 
    } 
    sleep(10); 
} 

答えて

2

あなたはDoSomethingのパラメータ、funcへの参照をキャプチャしています。
スレッドが実行されるまでに、そのパラメータの存続期間が終了しているため、ダングリング参照があり、使用すると未定義です。

+0

これは、DoSomethingに渡された関数がキャプチャリストに関する情報を保持していることを意味しますか? – 2power10

+0

@ 2power10あなたが何を求めているのか分かりません。参照でキャプチャする場合は、参照オブジェクトが使用時に有効であることを確認する必要があります。そうでない場合、プログラムは未定義です。価値によって取り込むことは、ここでは正しいことです。 – molbdnilo

0

スレッドオブジェクトtDoSomething()は、値渡しのオブジェクトfuncへの参照を受け取ります。 func()が実行されると、std::unique_lock<std::mutex> lock(mtx);の呼び出しによってmutexを待機している可能性があります。その間に、t.detach()が呼び出され、値のパラメータfuncが破棄されて機能が終了します。これは@molbidniloによって言われたような参照をぶら下げます。

t.detach()の代わりにt.join();を呼び出して問題を解決できます。

+0

't.join()'を使うと 'DoSomething'がブロックされるので、ここでは' t.detach() 'を使います。私は問題が参照の代わりに値でfuncをキャプチャすることによって解決できると思います。 – 2power10

0

t.detach()を使用すると、スレッドが独立して実行されているため、参照によって関数オブジェクトが渡されるため、独立スレッドが参照しようとしているときに関数オブジェクトが破棄された場合、プログラムの ですが、値で関数オブジェクトを渡すと、この問題は解決されます。私はあなたのコードを私のマシンでテストしましたが、渡された関数オブジェクトを参照で使用するとクラッシュしました。

関連する問題