0

マルチスレッド プログラムを作成していますが、複数のスレッドでグローバル関数を呼び出す必要がある場合があります

writeLog(const char* pMsg);

writeLog は次のように実装されます。

void writeLog(const char* pMsg)
{
   CRITICAL_SECTION cs;

   // initialize critical section
   ...

   EnterCriticalSection(&cs);

   // g_pLogFilePath is a global variable.
   FILE *file;
   if (0!=fopen_s(&file, g_pLogFilePath, "r+"))  
      return;

   fprintf(file, pMsg);

   fclose(file):
   LeaveCriticalSection(&cs);
}

私の質問は次のとおりです。

1) is it the best way to do concurrent logging? i.e., using critical section.

2) since I will write log in many places in the threads, 
and since each log writing will involve open/close file,
does the io will impact the performance significantly?

ありがとう!

4

4 に答える 4

4

同時ロギングを行う最善の方法は、C++ 用の既存のログ ライブラリの1 つを使用することです。おそらく使いたいと思う多くの機能があります (さまざまなアペンダー、フォーマット、同時実行性など)。

それでも独自のソリューションが必要な場合は、おそらく次のようなものを使用できます。一度初期化して状態を保持する単純なシングルトン (ファイル ハンドラーとミューテックス)

class Log
{
public:

    // Singleton
    static Log & getLog() 
    {
        static Log theLog;
        return theLog;
    }

    void log(const std::string & message)
    {
         // synchronous writing here
    }
private:
    // Hidden ctor
    Log()
    {
         // open file ONCE here
    }

    // Synchronisation primitive - instance variable
    // CRITICAL_SECTION or Boost mutex (preferable)
    CRITICAL_SECTION cs_;

    // File handler: FILE * or std::ofstream
    FILE * handler_;
};
于 2012-09-11T04:50:44.010 に答える
3

あなたの質問に答えるには:

  1. はい、並行ロギングにはクリティカルセクションが実際に必要です。

  2. はい、ロギングは確かにパフォーマンスに影響を与える可能性があります。

コメントで述べたように、クリティカルセクションを「保護」するために使用されるオブジェクトは、グローバル変数やシングルトンなど、すべてのスレッドからアクセスできる必要があります。

ロギングパフォーマンスに関しては、IOはコストがかかる可能性があります。一般的なアプローチの1つは、ログに記録するメッセージをバッファリングし、バッファがいっぱいになったときにのみ書き込むロギングオブジェクトを用意することです。これはパフォーマンスに役立ちます。さらに、いくつかのログレベル(DEBUG、INFO、WARNING、ERROR)を検討してください。

于 2012-09-11T05:07:02.747 に答える
2

はい、CSはロギングを保護するための合理的な方法です。すべてのスレッドからのすべての呼び出しでオープン/書き込み/クローズを行わないようにするために、文字列を別のログスレッドにキューに入れるのが一般的です(まだmalloced / newされていない場合は、コピーする必要があります)。ブロッキングディスクの遅延は、ロギング呼び出しからバッファリングされます。怠惰な書き込みなどの最適化は、ログスレッドで実装できます。

または、他の投稿者が示唆しているように、これらすべてがすでに実装されているロギングフレームワークを使用するだけです。

于 2012-09-11T07:57:12.300 に答える
1

返事を書いていたらブレーカーが落ちた。私の答えはまだ下書きなので、続けても構いません。シングルトンクラスを提供する回答とほぼ同じですが、もう少しCに似ています。これはすべて別のソース ファイルにあります (Logging.cppたとえば)。

static CRITICAL_SECTION csLogMutex;
static FILE *fpFile = NULL;
static bool bInit = false;

bool InitLog( const char *filename )
{
    if( bInit ) return false;
    bInit = true;
    fpFile = fopen( filename, "at" );
    InitializeCriticalSection(&csLogMutex);
    return fpFile != NULL;
}

void ShutdownLog()
{
    if( !bInit ) return;
    if( fpFile ) fclose(fpFile);
    DeleteCriticalSection(&csLogMutex);
    fpFile = NULL;
    bInit = false;
}

それらはアプリケーションの入口/出口で呼び出されます... ロギングに関しては、printf スタイルのロギングを実行できるように、可変引数リストを使用することを好みます。

void writeLog(const char* pMsg, ...)
{
   if( fpFile == NULL ) return;

   EnterCriticalSection(&csLogMutex);

   // You can write a timestamp into the file here if you like.

   va_list ap;
   va_start(ap, pMsg);
   vfprintf( fpFile, pMsg, ap );
   fprintf( fpFile, "\n" );        // I hate supplying newlines to log functions!
   va_end(ap);

   LeaveCriticalSection(&csLogMutex);
}

DLL 内でログを記録する予定がある場合、この静的な方法は使用できません。_fsopen代わりに、でファイルを開き、読み取り/書き込み共有を拒否する必要があります。

fflushアプリケーションがクラッシュすることが予想される場合は、定期的に呼び出すこともできます。または、ログをリアルタイムで外部から監視する場合は、毎回呼び出す必要があります。

はい、クリティカル セクションによるパフォーマンスへの影響はありますが、ファイルへの書き込みのパフォーマンス コストに比べれば大したことではありません。1 秒間に何千回もクリティカル セクションに入ることができますが、心配する必要はありません。

于 2012-09-11T05:36:21.100 に答える