14

私はC ++を初めて使用し、さまざまなライターがオブジェクトをスタックにプッシュし、リーダーがスタックからそれらをプルする(または少なくともオブジェクトへのポインターをプッシュする)マルチスレッドアプリを作成しています..

ロックコードなどを追加せずにこれを処理できる C++ に組み込まれた構造はありますか? そうでない場合、Boost ライブラリはどうですか?

編集:

やあ。最初の素晴らしい回答をありがとう。これが組み込み可能だと思った理由の 1 つは、私が純粋に x86 空間で考えていて、ポインターの PUSH/POP は命令レベルでのアトミック アクションであるべきだと考えていたからだと思います。

私の最初の予感が正しいかどうかはわかりませんが、これはすべてのプラットフォームで必ずしも正しいとは限りません。ただし、x86 で実行している場合、アトミック PUSH と POP をスタックに取得しますか?もしそうなら、これは本質的にロックフリーになりますか?

4

7 に答える 7

23

うん: Boost.Threadは素晴らしく、あなたのニーズにぴったり合うはずです。(最近では、多くの人が、Boost をほぼ組み込み機能と見なすことができると言っています。)

すぐに使用できるクラスはまだありませんが、同期プリミティブが手元にあれば、独自のスレッドセーフなラッパーを実装するのは非常に簡単std::stackです。次のようになります (すべてのメソッドを実装しているわけではありません...):

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;
}    

C++ を初めて使用する場合は、RAIIについて学んでください。このケースに関連して、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 を使用する必要があります (構文は Boost から直接ではありません)。

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

ポイントは、scoped_lockオブジェクトがスコープ外になると、そのデストラクタがリソース (この場合はロック) を解放することです。returnこれは、例外をスローしてスコープを終了するか、同僚が関数の途中でこっそり追加した奇妙なステートメントを実行するか、単に関数の最後に到達するかによって、常に発生します。

于 2009-04-26T11:50:16.530 に答える
5

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

于 2009-04-26T09:41:12.783 に答える
1

C ++でもBoostライブラリでもこれをサポートする組み込みのメカニズムはありません(注:Boostスタイルでスレッドセーフなスタックなどを作成している人もいます)。コードを借りるか、独自の同期でクックする必要があります。

あなたのケースでは、おそらく、複数のライタースレッドがスタックにアクセスでき(ただし、特定の時点で1つだけ)、複数のリーダーがスタックにアクセスできる(多くの場合)シングルライターマルチリーダーガード(SWMRG)が必要であることに注意してください。特定の時点)。リヒターにはリファレンス実装があります。

于 2009-04-26T11:54:12.467 に答える
1

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

C# の例については、こちらを参照してください。

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

于 2009-04-26T12:12:39.427 に答える
1

私の知る限り、C++ の組み込みサポートはありません。シンプルな同期ツールを使用して、スタック操作を同期する必要があります。CriticalSection は、スレッドが同じプロセスに属している場合に行います。それ以外の場合は Mutex を使用します。

于 2009-04-26T09:41:47.293 に答える
0

Windows で実行している場合、SLIST はロックフリー スタックを実装します (構造体を使用SLIST_HEADER & SLIST_ENTRY)。

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

于 2009-05-28T10:15:20.467 に答える