2012-02-23 9 views
1

どのようにしてオブジェクトのstd :: vectorを作成できますか?各オブジェクトにはboost :: threadが内部にカプセル化されています。std :: boost :: threadでエンコードされたオブジェクトのベクトルはinsde

class INSTRUMENT { 
public: 
    INSTRUMENT() : m_thread(new boost::thread(&INSTRUMENT::Start, this)) { 
     x = "abc"; 
    } 
    ~INSTRUMENT() {} 
    void Start(); 
public: 
    std::string x; 
    boost::shared_ptr<boost::thread> m_thread; 
}; 

void INSTRUMENT::Start() { 
    try { 
     while (1) { 
      boost::this_thread::interruption_point(); 
      std::cout << "here " << x << std::endl; 
     } 
    } catch (boost::thread_interrupted &thread_e) { 
     std::cout << "exit " << x << std::endl; 
    } catch (std::exception &e) { 
    } 
} 

std::vector<INSTRUMENT> m_inst_vector; 

for (int i = 0; i < 5; i++) { 
    m_inst_vector.push_back(INSTRUMENT()); 
} 

コードは正常にコンパイルされますが、出力は「abc」ではなく、ほんの一部のガベージです。デバッグでは、.Push_back()が呼び出されるたびに〜INSTRUMENT()が呼び出されることがわかりました。

現在のデザインの制限のため、boost :: group_threadを使用しないようにしました。内部にスレッドを持つオブジェクトのstd :: vectorを持つことが可能かどうか、または同様のデザインへの提案が非常に役に立ちます。

私はSOで同様のスレッドを見つける。コンパイラでサポートされているmove-semanticsについて言及しましたが、それが何であるか説明しませんでした。 How can I add boost threads to a vector

ありがとうございます。

+0

私の答えを編集しました。 – vz0

答えて

3

このコードには2つの問題があります。

最初に、boost::threadオブジェクトが構築された直後にスレッドが実行を開始するので、アクセスするデータが事前に初期化されていることを確認する必要があります。つまり、スレッドを構築する前にメンバー初期化リストでxを初期化します。

第2に、スレッドはINSTRUMENTオブジェクトのthisポインタを使用するため、オブジェクトは特定のアドレスに関連付けられます。 std::vectorコピー周囲:push_backを呼び出すとオブジェクトがベクターにコピーされ、追加する要素を追加すると、新しいメモリブロックを確保して部屋を確保する必要がある場合、他の要素をコピーできます。これは、デストラクタ呼び出しの原因です。一時的に構築され、push_backがベクターにコピーされ、一時的に破壊されます。

この問題を解決するには、コピーが間違ったセマンティクスを持つため、INSTRUMENTオブジェクトを移動またはコピーできないようにする必要があります。これを行うには、コピーコンストラクタと代入演算子をプライベートおよび未実装にします(または、この新しいC++ 11コンストラクトをサポートしている最近のコンパイラを使用している場合は削除するか、またはboost::noncopyableから派生させます)。これを行うと、共有することができないため、スレッドのためにshared_ptrが不要になります。したがって、直接作成することができます。

INSTRUMENTをコピーできない場合は、ベクトルに直接格納することはできません。したがって、boost::shared_ptr<INSTRUMENT>などをベクターに使用してください。これにより、ベクターは、INSTRUMENTオブジェクトのアドレスに影響を与えずに、その要素を自由にコピーして再シャッフルし、最後に正しく破棄されるようにします。

class INSTRUMENT: boost::noncopyable { 
public: 
    INSTRUMENT() : x("abc"),m_thread(&INSTRUMENT::Start, this) { 
    } 
    ~INSTRUMENT() {} 
    void Start(); 
public: 
    std::string x; 
    boost::thread m_thread; 
}; 

void INSTRUMENT::Start() { 
    try { 
     while (1) { 
      boost::this_thread::interruption_point(); 
      std::cout << "here " << x << std::endl; 
     } 
    } catch (boost::thread_interrupted &thread_e) { 
     std::cout << "exit " << x << std::endl; 
    } catch (std::exception &e) { 
    } 
} 

std::vector<boost::shared_ptr<INSTRUMENT> > m_inst_vector; 

for (int i = 0; i < 5; i++) { 
    m_inst_vector.push_back(boost::shared_ptr<INSTRUMENT>(new INSTRUMENT)); 
} 
+0

ありがとうAntony。あなたのコードはまさに私が探していたもので、100%動作します。 – 2607

0

EDIT:コードに競合状態があります。スレッドはxが初期化される前に開始されます。

ベクトルをvector<boost::shared_ptr<INSTRUMENT> >に変更し、boost::shared_ptrINSTRUMENTから削除する必要があります。

class INSTRUMENT { 
public: 
    INSTRUMENT() { 
     x = "abc"; 
     m_thread = boost::thread(&INSTRUMENT::Start, this) 
    } 
    ~INSTRUMENT() {} 
    void Start(); 
public: 
    std::string x; 
    boost::thread m_thread; 
}; 

for (int i = 0; i < 5; i++) { 
    m_inst_vector.push_back(boost::shared_ptr<INSTRUMENT>(new INSTRUMENT())); 
} 
+0

あなたの返事をありがとう、私はまだ同じ問題がある〜INSTRUMENT()は、.push_back()が呼び出された後に呼び出されます。 m_inst_vector。push_back(boost :: shared_ptr (new Test())); – 2607

関連する問題