2011-12-17 13 views
2

私は、さまざまな種類のツール(GCC、LEX、YACC、...)を表すクラスを持っています。 各インスタンスにはツールを表す型が与えられ、特別な構成が許可されます。C++でスレッドセーフなメソッドを実装する適切な方法11

デフォルトの設定を処理するために、マップとベクトルのデフォルト値を格納しています。私は、そのクラスは、すべてのコンテキストで使用できるようにしたいと、それは私が次のことを実施し、レースを回避すること、スレッドセーフでなければならないであろう。

int Tool::addType(std::string typeName, 
     std::string typeFlagName) 
    throw (GP::Exceptions::LockAcquisitionException) 
{ 
    static std::timed_mutex mutex; 
    std::unique_lock<std::timed_mutex> lock{mutex}; 

    int typeId = 0; 

    if (lock.try_lock_for(std::chrono::microseconds(100))) 
    { 
     int typeId = typeNames.size(); 
     typeNames[typeId] = typeName; 
     typeFlagNames[typeId] = typeFlagName; 
    } 
    else 
    { 
     throw GP::Exceptions::LockAcquisitionException{"Unable to generate new type ID within 100 microseconds."}; 
    } 
    return typeId; 
} 

これは良い解決策である場合、または場合、私は知りたいのですが私は何かが恋しい。 これで問題が解決しない場合は、もう少し冗長な解決策がありますか?

+4

それは同時にタイプを追加すると二つの別々のスレッドを防ぐことができますが、それは* *他のスレッドと同時にタイプを追加することから、一つのスレッドを防ぐことはできませんタイプを取得しようとしています。それは私にとっては安全ではないようです。 。 。 – ruakh

+1

私はruakhに同意します。あなたは、オブジェクト全体とすべてのメンバー呼び出しのためのstd :: mutexメンバーを持つべきです。次に、単純なstd :: lock_guardを使用してください。 – Lalaland

+1

タイプは変更されず、1つだけ追加されます。読み取りアクセスによって競合状態が発生することはありません。 – Geoffroy

答えて

4

どうしてですか?

class tool 
{ 
    std::atomic<int> index_; 
    std::array<std::pair<std::string, std::string>, 2048> types_; // Should be more than enough room. 

    int addType(std::string typeName, std::string typeFlagName) 
    { 
     int id = index++; 

     if(id >= types_.size()) 
      throw GP::Exceptions{"To many types."}; 

     types_[id] = std::make_pair(typeName, typeFlagName); 

     return id; 
    } 

}; 

あなたはのstd ::ベクトルを使用してビット賢く、この作ると、それは大きなサイズのために再割り当てする必要がある場合にのみ、ロックを持つことができます。

注:throw()節はC++ 11では非推奨です。

+0

"std :: vectorを使って少しスマートにすることができ、より大きなサイズのために再割り当てが必要な場合にのみロックを設定できます。" - サイズを取得する前にロックせずにこれを行う方法はありません。 – jcoder

+0

@JohnB:問題は? – ronag

+0

メソッド宣言でスローを意味しますか?あなたの応答に感謝しますが、私は本当に回避策を使用していない完全なスレッドセーフティを実装したいと思いますが(ときにはより良いかもしれませんが) – Geoffroy

3

私の提案は次のようになります。

class tool 
{ 
    std::mutex myMutex; 

    std::vector<std::string> typeNames; 

    int addType(std::string typeName) 
    { 
     std::lock_guard myLock(myMutex); 
     typeNames.push_back(typeName); 
     return typeNames.size()-1; // 
    } 

    // Only hold lock when needed 
    void longComplexFunction(int f) 
    { 
     // Compute as much as possible before 
     int complexMagic = veryLongFunction(f); 

     { 
      std::lock_guard myLock(myMutex); 
      typeNames[complexMagic] += "s"; 
     } 
    } 

} 
+0

そしてlock_guardがロックを取得できないとどうなりますか? – Geoffroy

+0

ロックが有効になるまでスリープします。 – Lalaland

+0

ちょうど最後の質問ですが、私はゲッターのために何ができますか? boost :: shared_mutexのようなものがありますか?私はstd :: lock_guardと一緒に使うことができますか? – Geoffroy

関連する問題