2012-09-11 6 views
0

나는 여러 스레드 프로그램을 만드는 오전 여러 스레드가 전역 함수를동시 로그 파일 액세스/C++

writeLog(const char* pMsg); 

를 호출해야하고 WRITELOG이 tihs 같은 구현 뭔가있을 것입니다 :

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? 

감사합니다!

+2

'cs'가 지역 변수 인 경우,'writeLog'를 입력 할 때마다 새로운 임계 영역을 생성하고 (반환 할 때 누출됩니다), 따라서 중요한 섹션은별로 없습니다. –

+0

중요 섹션 개체는 전역이어야하며 [MSDN 참조] (http://msdn.microsoft.com/en-us/library/windows/desktop/ms686908%28v=vs.85%29.aspx)이어야합니다. –

답변

2

CS는 로깅을 보호하는 합리적인 방법이며, 예. 모든 스레드의 모든 호출시 열림/닫힘/닫힘을 피하기 위해 문자열 (아직 malloced/newed되지 않은 경우에는이를 복사해야 할 수도 있음)을 별도의 로그 스레드에 대기열에 넣는 것이 일반적입니다. 블로킹 디스크 지연은 로깅 호출로부터 버퍼링됩니다. 게으른 쓰기 등의 최적화는 로그 스레드에서 구현할 수 있습니다.

다른 포스터에서 제안한대로이 모든 것들이 이미 구현 된 로깅 프레임 워크 만 사용하십시오.

4

동시 로깅을 수행하는 가장 좋은 방법은 existing log library for C++ 중 하나를 사용하는 것입니다. 그들은 아마도 당신이 사용하고자하는 많은 기능을 가지고 있습니다 (다른 appenders, 포맷팅, 동시성 등).

여전히 자신의 솔루션을 가지고 싶다면 당신은 아마 이런 식으로 뭔가 할 수 : 한 번 초기화 귀하의 질문에 대답하기 위해 상태 (파일 핸들러와 뮤텍스)

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_; 
}; 
+0

그리고 생성자에서'InitializeCriticalSection' =을 잊지 마세요. – paddy

+0

@paddy : CRITICAL_SECTION을 선호한다면 - 그렇습니다. 하지만 나는 여전히 boost 뮤텍스 (또는 std :: 만약 당신이 현대 컴파일러를 가지고있다)를 추천 할 것이다. 초기화가 더 간단하고 로그 쓰기는 예외 안전입니다. – nogard

3

을 유지 간단한 싱글 :

  1. 예, 동시 로깅에는 필수 섹션이 필요합니다.

  2. 예, 로깅은 실제로 성능에 영향을 줄 수 있습니다.

설명에서 언급했듯이 중요한 섹션을 보호하는 데 사용되는 개체는 전역 변수 나 단독 개체와 같은 모든 스레드에서 액세스 할 수 있어야합니다.

로깅 성능과 관련하여 IO에 비용이 많이 소요될 수 있습니다. 한 가지 일반적인 접근 방식은 기록 할 메시지를 버퍼링하는 로깅 개체를 가지며 버퍼가 가득 차면 기록합니다. 이것은 성능에 도움이 될 것입니다. 또한 여러 로그 수준 (DEBUG, INFO, WARNING, ERROR)을 고려하십시오.

1

답변을 작성한 후 회로 차단기가 작동합니다. 내 대답은 여전히 ​​초안에 있기 때문에 계속할 수 있습니다. 싱글 톤 클래스를 제공하는 대답과 거의 같지만 좀 더 C와 비슷합니다. 이것은 별개의 소스 파일에 있습니다 (예 : Logging.cpp). 로깅을 위해, 나는 내가 printf와 스타일의 로깅을 할 수있는 변수 인수 목록을 사용하는 것을 선호으로

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

는 ... 응용 프로그램 입/출력에 호출됩니다.

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으로 전화 할 수도 있습니다. 또는 실시간으로 외부에서 로그를 모니터링하려면 매번 호출해야합니다.

예, 중요한 섹션의 성능에 영향을 미치지 만 파일에 쓰는 성능 비용과 비교하면 아무 것도 아닙니다. 초당 수천 번 크리티컬 섹션을 걱정없이 입력 할 수 있습니다.