2

私はこれに非常に慣れていないため、質問が明確でない場合はお詫び申し上げます。

C++ でスレッド セーフ ロガーを作成しました。このロガーは大規模なプログラムで使用され、複数の場所から呼び出されます。シングルトンを使用しているため、ロガーのインスタンスは 1 つしかありません。このロガーは、ファイルとコンソールに出力します。cout と同様に動作します。別のファイルから文字列を取り込み(必要に応じて連結します)、文字列が完了するまでピースをバッファに格納し、cout を使用して出力します。文字列は const char* として格納されています。現在、mutex は 1 つの関数でロックされ、別の関数でロック解除されています (これは私の問題でした)。これは endl 演算子をオーバーロードします。

私の問題は、ユーザーがロガーが呼び出されている他のファイルに endl を書き込む場合にのみ、この関数 (ミューテックスがロック解除されている場所) が機能することです。ユーザーはendlを使用しないか、頻繁に使用する可能性があるため、ユーザーの書き込みに依存しない汎用ユーティリティにする必要があります。バッファを空にできるように、ロガーが(他のファイルからの)文字列がいつ処理されたかを特定する手段が必要です。現在 endl はキーワードのようなもので、キーワードなしで機能させるには何らかの手段が必要です。

最初は、文字列内の「\ 0」終了文字をチェックし、そのチェックを使用して文字列が完了したことを確認し、バッファを空にする手段を見つけることができると考えていました。ただし、これを行うと範囲外のエラーが発生します。

お時間をいただきありがとうございます

4

3 に答える 3

4

状況がよくわかりませんが、プロキシが必要なようです。

class LogSingleton
{
public:
    LogSingleton& instance() { /* ... */ }

    void lock(); // lock mutex
    void unlock(); // unlock mutex

    template <typename T>
    friend LogSingleton& operator<<(LogSingleton& pLog, const T& pX)
    {
        // needs to be locked first
        assert(is_locked()); 

        /* output pX however */

        return pLog;
    }
};

class LogProxy
{
public:
    LogProxy()
    {
        // manage lock in proxy
        LogSingleton::instance().lock();            
    }

    ~LogProxy()
    {
        LogSingleton::instance().unlock();            
    }
};

// forward input into the proxy to the log, knowing it's locked
template <typename T>
LogProxy& operator<<(LogProxy& pProxy, const T& pX)
{
    LogSingleton::instance() << pX;

    return pProxy;
}

// now expose proxy
typedef LogProxy log;

そして、あなたはこれをするでしょう:

log() << "its locked now" << "and the temporary will die" << "here ->";

ロックはコンストラクタとデストラクタで行われ、最後にデストラクタが呼び出されます。


Tony が正しく指摘しているように、これはロックを不必要に長く保持します。ロックは、への「最終」出力にのみ必要ですLogSingleton。これを想像してください:

log() << "this next function takes 5 minutes"
        << my_utterly_crappy_function() << "ouch";

何もログに記録されていませんが、mutex は長時間ロックされています。出力をバッファリングしてから、一度にすべて出力することをお勧めします。

class LogProxy
{
public:
    ~LogProxy()
    {
        // manage lock in proxy
        LogSingleton::instance().lock();

        // no-throw, or wrap mutex use in a scoped-lock
        LogSingleton::instance() << mBuffer.rdbuf();

        LogSingleton::instance().unlock();            
    }

    // buffer output
    template <typename T>
    friend LogProxy& operator<<(LogProxy& pProxy, const T& pX)
    {
        mBuffer << pX;

        return pProxy;
    }

private:
    std::ostringstream mBuffer;
};

バッファが出力可能になるまで、ロックは取得されません。

于 2010-08-25T20:44:01.577 に答える
0

通常、ある関数でミューテックスをロックし、別の関数でロックを解除することはお勧めできません。同じ機能でロックとロック解除を行う必要があります。

私は似たようなものを作成し、通常はErrorというC++クラスを作成しました。

このようにして、ユーザーはErrorオブジェクトを作成し、そのエラーオブジェクトがすべての終了処理を処理します。次に、エラーオブジェクトがErrorLoggerのキューに送信され、ErrorLoggerキューが空になるとエラーロガーが終了します。ErrorLoggerにはキューから処理する時間がありますので、ミューテックスについて心配する必要はありません。

于 2010-08-25T20:36:55.300 に答える
0

https://web.archive.org/web/1/http://articles.techrepublic%2ecom%2ecom/5100-10878_11-5072104.htmlを確認 してください

アイデアは、実際のスレッドセーフロギング関数を呼び出すスレッドローカル「プロキシ」を作成することです。

于 2010-08-25T20:40:32.127 に答える