2

オーバーロードされたロギング クラスがありますoperator<<。だから私はこのようなことをすることができます:

oLogger << "Log this" << " and this" << " and " << 10 << endl;
oLogger`<< "Something else" << endl;

ロガーは問題なくこれを行います。しかし、ロガーオブジェクトをスレッド間で共有したい。次に、次のようなものを出力したくありません。

//LogFILE
Log this and this Something else
 and 10

したがって、operator<<s のチェーン全体をロックする必要があります。これは RAII でできると思いますが、まだあまり考えていません。それまでの間、これを行う従来の方法はありますか? (マニピュレーターで入力を終了する以外は?)

4

5 に答える 5

4

Nimの答えのわずかな代替:

作成

class LockedLog {
    static MutEx mutex; // global mutex for logging
    ScopedLock lock; // some scoped locker to hold the mutex
    Logger &oLogger; // reference to the log writer itself
public:
    LockedLog(Logger &oLogger) : oLogger(oLogger), lock(mutex) {}
    template <typename T>
    LockedLog &operator<<(const T &value) { oLogger << value; return *this; }
};

そして、次のいずれかを実行します。

LockedLog(oLogger) << "Log this" << " and this " << " and " << 10 << endl;

またはLogger::operator<<、通常のメソッドに変更し、 でこのメソッドを呼び出しLockedLog::operator<<、キャスト演算子を に追加しLoggerます。

operator LockedLog() { return LockedLog(*this); }

これにより、現在のコードにロックが追加されます。

更新:これはすべての呼び出しをロックし、引数の評価をロックすることoperator<<さえあります(コンパイラが最初に左または右の引数を評価し、選択するかどうかによって異なります)。それを減らすには、次のことができます。

class LockedLog {
    static MutEx mutex; // global mutex for logging
    std::stringstream buffer; // temporary formatting buffer;
    Logger &oLogger; // reference to the log writer itself
public:
    LockedLog(Logger &oLogger) : oLogger(oLogger), lock(mutex) {}
    template <typename T> 
    LockedLog &operator<<(const T &value) { buffer << value; return *this; }
    ~LockedLog() { ScopedLock lock(mutex); oLogger << buffer.str() << std::flush; }
};

しかし、stringstream別のオーバーヘッドが追加されます。

于 2011-02-10T09:57:36.887 に答える
3

1つのアプローチは、マクロを使用することです。

#define LOG(x) \
{\
  <acquire scoped lock> \
  oLogger << x; \
}

それから

LOG("Log this" << " and this" << " and " << 10 << endl);

また、上記のマニピュレータアプローチを使用して実行しましたが、問題は、operator<<すべてのタイプに実装する必要があることです(つまり、既存の標準演算子を使用できません)。

編集:ロックが保持される時間を短縮するには、次のようなことを検討してください:

#define LOG(x) \
{\
  std::ostringstream str; \
  str << x; \       // the streaming happens in local scope, no need for lock
  oLogger.write(str.str()); \ // ensure the write method acquires a lock
}
于 2011-02-10T09:13:09.377 に答える
2

最善の解決策は、クラスを作成してbuffer

buffer(oLogger) << "Log this" << " and this" << " and " << 10 << endl;

一時バッファ オブジェクトを作成し、出力をキャプチャしてフォーマットし、デストラクタで oLogger に書き込みます。これは、 a をラップすることで簡単に実行できstringstreamます。すべてのスレッドには独自のバッファーがあるため、フォーマットは独立しています。

さらに空想的には、buffer::~bufferいくつかの異なるメカニズムを使用して、 へのスレッドセーフでないアクセスを防ぐことができますoLoggeroperator<<複数のスレッドからの呼び出しがインターリーブされる可能性があると想定しました。実際、それはさらに悪いことです。それらは同時に発生する可能性があります。「LSoogm ethhiinsg else」を取得できます。一度に 1 つだけbufferフラッシュするようoLoggerにすることで、これを防ぐことができます。

于 2011-02-10T10:36:13.697 に答える
2

ここではおそらく式テンプレートを使用します。

主なアイデアは、特にこのフォーマット中に関数呼び出しがある可能性があるため、フォーマット段階でロックを取得するのはばかげているということです。

2 つの異なるフェーズを使用する必要があります。

  • ログをフォーマットする
  • アトミックにログを投稿する

これは、式テンプレートを使用して実現できます。

  1. への最初の呼び出しは、への参照を埋め込む aをLogger::operator<<生成します。LoggerBufferLogger
  2. LoggerBufferすべてのフォーマットの混乱を処理する後続の呼び出しが実行されます
  3. LoggerBuffer(ステートメントの最後で) が破棄されると、 がロックLoggerされ、フォーマットされた文字列が渡され、ロックが解除されます (ロックのないキューなどがない限り)。
于 2011-02-10T10:44:11.377 に答える
1

ログを国際化する必要があるため、次のようなものを好みます。

oLogger << myAutosprintf(_("My wonderful %s ! I have %d apples"), name, nbApple);

翻訳にははるかに優れています:)そして、それはあなたの問題を解決します。_()翻訳用のショートカットです。

gnu::autosprintfboost.format (Jan Huec に感謝) を使用するか、独自に作成することができます。

my2c

注意:良い発言の後に編集しました(速すぎました、コメントありがとうございます)。間違った「最初の部分」のステートメントを削除しました

于 2011-02-10T09:15:52.550 に答える