2017-09-12 9 views
6

いくつかのコードを非同期的に実行するクラスがあり、非同期コードがそのクラスインスタンスを使用して呼び出しメンバ関数、読み取りデータメンバなどを行うとすると、明らかに、クラスインスタンスはバックグラウンドスレッドよりもアクセス時間が長くなければなりません安全であるために。デストラクタのバックグラウンドスレッドに参加することでこれを保証すれば十分ですか?たとえば:デストラクタに参加して非同期作業を待つのは安全ですか?

#include <iostream> 
#include <thread> 

class foo final 
{ 
public: 
    foo() = default; 

    void bar() { 
     std::cout << "Hopefully there's nothing wrong with using " << this << "\n"; 
    } 

    void bar_async() { 
     if (!m_thread.joinable()) { 
      m_thread = std::thread{&foo::bar, this}; 
     } 
    } 

    ~foo() { 
     if (m_thread.joinable()) { 
      std::cout << "Waiting for " << m_thread.get_id() << "\n"; 
      m_thread.join(); 
     } 
    } 

private: 
    std::thread m_thread; 
}; 

int main() { 
    foo f; 
    f.bar_async(); 
} 

は具体的に、私はobject lifetime rules心配:

デストラクタ些細なことではないクラスのいずれかのタイプのオブジェクトの場合、デストラクタの実行が開始されると寿命が終了します。

...オブジェクトの有効期間が終了したと、オブジェクトが占有ストレージを再利用またはリリースされる前に、そのオブジェクトを識別glvalue式の以下の用途が未定義された後:...

  • 非静的データメンバーへのアクセスまたは非静的メンバー関数への呼び出し。

しかし私には、上記の厳密な読書も~foo()内部からthis->bar()を呼び出すと、直接「明らかに」そうではありませんこれは、未定義であることを暗示します。

+1

'final'は多くの問題を解決します。あなたが「最終的」でない場合は、非常に注意してください。 – Yakk

+0

これは実用的か法律的な質問ですか? – curiousguy

+0

@curiousguy Legalistic –

答えて

3

cppreferenceは正しいですが、デストラクタの内部からではなく、オブジェクトからメンバーにアクセスすることについて話しています。我々は[class.cdtor]/1を見れば、我々はコンストラクタがで実行結果を開始する前に

非自明なコンストラクタを持つオブジェクトについて

は、オブジェクトの任意の非静的メンバまたはベースクラスを参照していることがわかり未定義の動作。非些細なデストラクタを持つオブジェクトの場合、デストラクタが実行を終了した後にオブジェクトの非静的メンバまたは基本クラスを参照するは、未定義の動作になります。

強調鉱山

だから、限り、我々はデストラクタであると我々はまだデストラクタ端の範囲まで破壊されないものとメンバーのオブジェクトを操作することができます。

スレッドでjoinを呼び出しても問題ありません。もしそうでなければ、ロックガードのようなものは、それらが参照するミューテックスへのアクセスが未定義の振る舞いであったなら、役に立たないでしょう。

+0

右、私は特にデストラクタのコードを心配していません。実際にはbar()が他のスレッドから呼び出されています。デストラクタと同時に実行される可能性があります。 –

+0

@TavianBarnes他のスレッドは何ですか?メンバースレッドを開始するには 'bar_async()'を呼び出さなければなりません。あなたの例では、オブジェクトが破壊されるのと同時にこの関数を呼び出すことはできません。 – NathanOliver

+0

メンバスレッドは 'bar()'を呼び出しています –

0

私の直感はノーです。これは、thread :: joinが例外をスローする可能性があり、デストラクタからエスケープする例外を望んでいないためです。それはtryキャッチでラップし、例外を適切に処理しても大丈夫かもしれません。

+3

これらの例外の原因は、基本的にプログラミングエラーです。自分自身に参加しようとしているか、結合できないスレッドに参加しようとしています。 – MSalters

+0

例外がキャッチされず、スローされたスレッドで処理された場合、スレッド内の例外はただちにプログラムを終了します。 - そのスレッドに参加するデストラクタはまったく影響を受けません。 – CAF

関連する問題