2009-04-26 19 views
14

私はC++の新機能で、異なるライターがスタックにオブジェクトをプッシュし、それらをスタックからプルする(または少なくともオブジェクトへのポインタをプッシュする)マルチスレッドアプリケーションを作成しています..スレッドセーフなC++スタック

ロックコードなどを追加せずにこれを処理できる構造体がC++に組み込まれていますか?もしそうでなければ、Boostライブラリはどうですか?

編集:

こんにちは。最初の偉大な答えをありがとう。私はこれが組み込み可能であると思った理由の1つは、私がx86空間で純粋に考えていることであり、ポインタのプッシュ/ポップは命令レベルでのアトミックアクションでなければならないと思っていました。

私の初期の勘違いが本当であるかどうかはわかりませんが、これは必ずしもすべてのプラットフォームで当てはまるとは限りません。 x86上で実行している場合は、スタックにアトミックなPUSHとPOPを取得しますか?そうであれば、基本的にロックフリーになっていますか?

+0

x86 PUSH/POP命令のアトミシティに興味がある場合は、スタックデータ構造にアクセスするためにこのような命令を使用しないC++とは何の関係もありません。 –

+2

委員会は、TR1の必須のコンパイラ(おそらくTR2でさえない)のために、原子レベルの、より良いメモリモデルの抽象化を行うのではなく、DDJの並列説教クラスを書く方が忙しいです。 答えます:あなたは本当にプッシュしてポップしないので、スレッド間で暗黙的にレジスタを変更すると、現在異なるコアで実行されています。 :-)良いショットですが、うまくいきません。ロックフリーでも、少なくともCASハンマーなしではできません。 C++ zealotsの場合:既存のコヒーレンシープロトコルを定義して同意し、新しい開発のためのいくつかの範囲を残すだけです。 –

+0

関心のある人は原子操作を見て、Intelはcmpxchg16bを介してDCASをサポートしています。残念ながら、AMDにはcmpxchg8bしかありません。私はIntelマシンのために書いているので、私にとって重要ではありません:) – bugmenot77

答えて

21

はい:Boost.Threadは素晴らしいですし、あなたのニーズに非常によく合うはずです。 (最近、多くの人がBoostをビルトイン機能として数えることができると言っています)。

すぐに使用できるクラスはありませんが、手元に同期プリミティブがあれば実際には、スレッドセーフなラッパーを実装するのは非常に簡単です(たとえば、std::stack)。あなたがC++に慣れていない場合、およそRAIIを学ぶください

template <typename T> class MyThreadSafeStack { 
    public: 
    void push(const T& item) { 
     boost::mutex::scoped_lock lock(m_mutex); 
     m_stack.push(item); 
    } 
    void pop() { 
     boost::mutex::scoped_lock lock(m_mutex); 
     m_stack.pop(); 
    } 
    T top() const { // note that we shouldn't return a reference, 
        // because another thread might pop() this 
        // object in the meanwhile 
     boost::mutex::scoped_lock lock(m_mutex); 
     return m_stack.top(); 
    } 

    private: 
    mutable boost::mutex m_mutex; 
    std::stack<T> m_stack; 
}  

:それは、この(すべてのメソッドを実装していない...)のようになります。このケースに関連して、Boost.Threadはロックを解除することを忘れることによって脚に身を投げ込むのを困難にする "スコープロック"クラスを持っています。

あなたは今まで自分がこのようなコードを書いて見つけた場合:

void doStuff() { 
    myLock.lock(); 
    if (!condition) { 
    reportError(); 
    myLock.unlock(); 
    return; 
    } 
    try { 
    doStuffThatMayThrow(); 
    } 
    catch (std::exception& e) { 
    myLock.unlock(); 
    throw e; 
    } 
    doMoreStuff(); 
    myLock.unlock(); 
} 

、(ブーストから構文直接ではなく)、あなたはただノーと言うべきであり、代わりにRAIIを行く:

void doStuff() { 
    scoped_lock lock; 
    if (!condition) { 
    reportError(); 
    return; 
    } 
    doStuffThatMayThrow(); 
    doMoreStuff(); 
} 

ポイントscoped_lockオブジェクトが有効範囲外になると、そのデストラクタはリソース(この場合はロック)を解放します。これは、例外をスローしてスコープを終了するかどうかにかかわらず、または関数の途中で仲間が巧妙に追加した奇数returnステートメントを実行することによっても、いつでも起こります。

+0

恐ろしい答え。ありがとう、これは非常に明確な答えと非常に役立った! – bugmenot77

+0

あなたは大歓迎です。私が助けられたら嬉しいよ! – Reunanen

+2

mutexによってロックされていても、stdコンテナはスレッドセーフではないことに注意してください。その理由は、それらの変更が既存のイテレータを無効にするからです。 – ASk

4

現在のC++標準ではスレッド化がまったく扱われていないため、最初の質問に対する答えは「いいえ」です。また、一般的には、データ構造を正しくかつ/または効率的に実行するのに十分な情報がないため、基本的なデータ構造にロックを組み込むことは好ましくありません。代わりに、データ構造を使用するクラス、つまり独自のアプリケーションクラスでロックを実行する必要があります。

+1

私はソートオブソート(downvoteではありません)しなければなりません。プライベートなstd :: stackインスタンスをラップするクラスThreadSafeStackを書くことは大丈夫だと思います。次に、各メソッド(プッシュ、ポップ、...)の初めにクリティカルセクションなどを入力します。 top()は参照を返すべきではなく、むしろコピーを返すべきです。これは効率の低下を引き起こしますが、私の意見では、アプリケーションクラスを書くことの容易さは非常に価値が高いことがよくあります。また、そうでない場合(例えば、巨大なオブジェクトがコピーされている場合)には、ラッパークラスを使用しないでください。 – Reunanen

+0

はい、それは私が意図したものですが、恐らくひどく表現されている - ThreadSafeStackはアプリケーションのクラスの1つです。しかし、汎用ライブラリは、(IMHO)そのようなクラスを提供すべきではありません。 –

+1

ああ、大丈夫です。私は、主にビジネスロジックを含むものとしてアプリケーションクラスを考えていました。 – Reunanen

1

AFAIK、C ​​++でサポートされていません。シンプルな同期ツールを使用してスタック操作を同期させる必要があります。 CriticalSectionはスレッドが同じproceassに属し、そうでなければMutexに行く場合に実行されます。

1

これをC++やBoostライブラリでサポートする組み込みのメカニズムはありません(注:一部の人はthread-safe stacks/etc. in the Boost styleと書いています)。いくつかのコードを借りたり、独自の同期で調理する必要があります。

あなたのケースでは、おそらく、複数のライタースレッドがスタックにアクセスできる(ただし、特定の時点で1つだけ)、複数のリーダーがそのスタックにアクセスできるシングルライターのマルチリーダーガード(SWMRG)スタック(特定の時点で多くの場合)。リヒターはreference implementationです。

1

ロックを使用しない場合は、ロックフリーのスタックを使用する必要があります。これは実際にはそれほど難しくありません(ロックフリーのキューは難しい)。 Windows上でInterlockedCompareExchangeなどのプラットフォーム固有の比較交換プリミティブが必要ですが、抽象化するのは難しくありません。

は、C#の例は、ここを参照してください:あなたがWindows上で実行している場合

http://www.boyet.com/Articles/LockFreeRedux.html

0

、SLISTは(構造SLIST_HEADER & SLIST_ENTRY付き)lockfreeスタックを実装しています。

アルゴリズムは、インターロックされた関数を使用して、かなり簡単なプッシュ/ポップの単独リンクリストスタックを使用して実装されています。明らかではない唯一の項目は、ABAの問題を回避するためのカウンタ増分です。

+0

ありがとうございます。これが他の人にとって有益だと思う。私はLinuxで走っていて、上記のスコープロックソリューションを使用していました。最後に、私は構造ではなくコードにロッキングコードを入れました。 – bugmenot77

関連する問題