2016-09-13 20 views
2

、私はboost::mutexのベクトル、制御インスタンスが所有する各1(奇妙なコード設計が、MWEの目的のみのために)lockしたいと思います。ブースト:: scoped_lockのRAIIの挙動

// std::vector<Controlled*> _vData; 

void Container::main_method() 
{ 
    for (int i=0; i<_vData.size(); i++) 
    { 
    boost::mutex::scoped_lock my_lock(_vData.at(i)->_mutex); 
    this->processing(i); 
    } 

    // precondition for post_processing(): all processing() calls done 
    for (int i=0; i<_vData.size(); i++) 
    { 
    boost::mutex::scoped_lock my_lock(_vData.at(i)->_mutex); 
    this->post_processing(i); 
    } 
} 

しかしprocessingので、CPUバウンドとオブジェクトが他の場所での平均時間内から変更されている制御されて、私は単にをロックするために、main_methodの先頭に循環scoped_lockをしたいと思いますこのよう

void Container::desired_main_method() 
{ 
    for (int i=0; i<_vData.size(); i++) 
    { 
    boost::mutex::scoped_lock my_lock(_vData.at(i)->_mutex); 
    } 

    // locks destroyed here, aren't they ? 

    for (int i=0; i<_vData.size(); i++) 
    { 
    this->processing(i); 
    } 

    for (int i=0; i<_vData.size(); i++) 
    { 
    this->post_processing(i); 
    } 
} 

など、すべてできるだけ早く、私はよくRAIIイディオムとscoped_lockコンテキストをunderstanded場合は、問題は、トンでありますこのようにして、ロックはロックが完了した直後に範囲外に出るでしょう。forサイクルが終了します。

私はコンテナ CTORでnewロックの配列にしようとしたとdeleteにはそれにそのデストラクタで、私はこれはRAIIイディオム自体に反していると思います。

私は何を誤解したのですか、それともどのように問題全体をリファクタリングできますか?

答えて

2

あなたの質問は、であると仮定します。「複数のミューテックスに対してRAIIのようなスコープ付きロックを同時に使用するにはどうすればよいですか?

次に、複数のロックに対して独自のRAIIラッパーを作成するか、scope guardのようなものを使用できます。 (未テスト擬似コードが、あなたのアイデアを得る願っています)

template <typename TIterator> 
class multiple_lock_guard 
{ 
private: 
    TIterator _begin, _end; 

    multiple_lock_guard(TIterator begin, TIterator end) 
     : _begin{begin}, _end{end} 
    { 
     for(auto it = _begin; it != _end; ++it) 
     { 
      it->_mutex.lock(); 
     } 
    } 

    ~multiple_lock_guard() 
    { 
     for(auto it = _begin; it != _end; ++it) 
     { 
      it->_mutex.unlock(); 
     } 
    } 
}; 

次のようにあなたはそれを使用することができます。以下程度

void Container::desired_main_method() 
{ 
    multiple_lock_guard mlg(std::begin(_vData), std::end(_vData)); 

    for(int i = 0; i < _vData.size(); i++) 
    { 
     this->processing(i); 
    } 

    for(int i = 0; i < _vData.size(); i++) 
    { 
     this->post_processing(i); 
    } 
} 
+0

なぜあなた自身で記述しますか?標準ライブラリには( 'std :: lock'と' defer_lock_t'を取り囲む)多くの機能があります。 Boostはiterator-rangeインターフェース(私の答えを見てください)を使うとさらに強力になります。あなたの実装が自然にデッドロックを起こしやすいので、もっと頑強になることに注意してください。 – sehe

+0

@sehe:公正なポイント - 私の答えは、OPに "複数のロックガード"問題をどのように解決できるかを示すことを目的としています同様の問題と、独自のRAIIラッパーの実装方法を示しています。 –

1

どのように?

void Container::desired_main_method() 
{ 
    std::vector<boost::mutex::scoped_lock> locks; 

    for (int i=0; i<_vData.size(); i++) 
    { 
    locks.emplace_back(_vData.at(i)->_mutex); 
    } 

    for (int i=0; i<_vData.size(); i++) 
    { 
    this->processing(i); 
    } 

    for (int i=0; i<_vData.size(); i++) 
    { 
    this->post_processing(i); 
    } 
} 
0

あなたはすでにアトミック延期ロックのコレクションロックするブーストスレッドからフリー機能拡張を使用することができます。このオーバーロードを提供していません++ 17 C、悲しいことに

Live On Coliru

#include <boost/thread.hpp> 
#include <vector> 

struct X { 
    boost::mutex mutable mx; 
}; 

void foo(std::vector<X> const& xs) { 

    std::vector<boost::unique_lock<boost::mutex> > locks; 
    for (auto& x : xs) { 
     locks.emplace_back(x.mx, boost::defer_lock); 
    } 

    boost::lock(locks.begin(), locks.end()); 

    // all locks held 
} 

int main() { 
    std::vector<X> xs(10); 
    foo(xs); 
}