18

coutとcerrを介してコンソールに書き込むOpenMPスレッドがあります。もちろん、これは安全ではありません。出力をインターリーブできるからです。私は次のようなことをすることができます

#pragma omp critical(cerr)
{
   cerr << "my variable: " << variable << endl;
}

valgrind DRDマニュアル( http://valgrind.org/docs/manual/drd-manual.html#drd-manual.effective-)で説明されているアプローチと同様に、cerrをスレッドセーフバージョンに置き換えることができればもっと良いでしょう。std ::ostreambufからクラスを派生させることを含む)を使用します。理想的には、最終的には、cerrを自分のスレッド化されたcerrに置き換えるだけです。

tcerr << "my variable: " << variable << endl;

このようなクラスは、「endl」に遭遇するとすぐにコンソールに出力できます。異なるスレッドからの行がインターリーブされていてもかまいませんが、各行は1つのスレッドからのみ取得する必要があります。

C ++でのこのストリーミングがどのように機能するのか、私にはよくわかりません。複雑すぎます。誰かそのようなクラスがありますか、またはその目的のためにそのようなクラスを作成する方法を教えてもらえますか?

4

5 に答える 5

42

他の人が指摘したように、C++11 ではstd::cout スレッドセーフです。

ただし、次のように使用すると

std::cout << 1 << 2 << 3;

異なるスレッドを使用しても、出力は引き続きインターリーブ<<できます。これは、すべてが新しい関数呼び出しであり、別のスレッドの関数呼び出しが先行する可能性があるためです。

すべてをロックするaなしのインターリーブを回避するには、次のようにします。#pragma omp critical

std::stringstream stream; // #include <sstream> for this
stream << 1 << 2 << 3;
std::cout << stream.str();

ストリームに 123 を書き込む 3 つの呼び出しは、ローカルの非共有オブジェクトに対して 1 つのスレッドでのみ発生しているため、他のスレッドの影響を受けません。次に、アイテム 123 の順序が既に固定されている共有出力ストリームへの呼び出しが 1 回だけあるstd::coutため、めちゃくちゃになることはありません。

于 2013-02-22T22:52:02.153 に答える
14

文字列ビルダーと同様のアプローチを使用できます。次のような非テンプレート クラスを作成します。

  • operator<<このオブジェクトへの挿入用にテンプレート化されたオファー
  • 内部的にstd::ostringstream
  • 破棄時にコンテンツをダンプします

大まかなアプローチ:

 class AtomicWriter {
    std::ostringstream st;
 public:
    template <typename T> 
    AtomicWriter& operator<<(T const& t) {
       st << t;
       return *this;
    }
    ~AtomicWriter() {
       std::string s = st.str();
       std::cerr << s;
       //fprintf(stderr,"%s", s.c_str());
       // write(2,s.c_str(),s.size());
    }
 };

使用:

AtomicWriter() << "my variable: " << variable << "\n";

または、より複雑なシナリオでは:

{
   AtomicWriter w;
   w << "my variables:";
   for (auto & v : vars) {
      w << ' ' << v;
   }
}  // now it dumps

マニピュレータが必要な場合は、さらにオーバーロードを追加する必要があります。デストラクタでのアトミックな書き込みwriteよりも適切に使用できます。または、宛先がコンストラクタ ( /file descriptor/ ) に渡されるように一般化できます。fprintfstd::cerrstd::ostreamFILE*

于 2013-02-22T22:42:42.853 に答える
0

を継承することでそれを行うことができstd::basic_streambuf、正しい関数をオーバーライドしてスレッドセーフにすることができます。次に、このクラスをストリーム オブジェクトに使用します。

于 2013-02-22T22:00:52.777 に答える