2017-04-15 4 views
0

So habe ich mehrere Threads in die gleiche Datei schreiben durch Aufruf von Log :: write method.C++: Schreiben in eine Datei im Multithread-Programm

class Log 
{ 
private: 
    ofstream log; 
    string file_path; 
public: 
    Log(string); 
    void write(string); 
}; 
Log::Log(string _file_path) 
{ 
    file_path=_file_path; 
} 
void Log::write(string str) 
{ 
    EnterCriticalSection(&CriticalSection); 
    log.open(file_path.c_str(),std::ofstream::app); 
    log<<str+'\n'; 
    log.close(); 
    LeaveCriticalSection(&CriticalSection); 
} 

Ist es sicher, wenn Threads Log :: Schreibverfahren des gleichen Objekts zur gleichen Zeit nennen?

+1

Ja. Ziehen Sie in Erwägung, RAII zu verwenden, um den kritischen Abschnitt zu sperren/entsperren, um ihn als Ausnahme sicher zu machen. Erwägen Sie die C++ - Standardsperrung. Erwägen Sie die Verwendung eines separaten Protokollierungsthreads und einer Nachrichtenwarteschlange, um den Engpass bei der Sperrung zu verringern. Beachten Sie, dass das Öffnen von Dateien (unter MS Windows) eine sehr teure Operation ist - erwägen Sie, die Protokollierungsklasse in einen Singleton zu ändern und die Datei nur einmal zu öffnen. –

+1

Verwenden Sie eine Protokollierungsbibliothek von Drittanbietern – ZivS

Antwort

1

Ihr Code ist verschwenderisch und folgt nicht den C++ - Idiomen.

Beginnend vom Ende: ja, write ist threadsicher, weil win32 CRITICAL_SECTION es vor gleichzeitigen Änderungen schützt.

obwohl:

  1. warum öffnen und schließen jedes Mal, wenn der Strom? Das ist sehr verschwenderisch. Öffne den Stream im Konstruktor und lasse ihn geöffnet. Der Destruktor kümmert sich um das Schließen des Streams.

  2. Wenn Sie Win32 kritischen Abschnitt verwenden möchten, mindestens machen es RAII sicher. Erstellen Sie eine Klasse, die einen Verweis auf den kritischen Abschnitt umschließt, indem Sie sie in einem Konstruktor sperren und im Destruktor entsperren. Auf diese Weise, selbst wenn eine Ausnahme ausgelöst wird - Sie werden garantiert, dass die Sperre entsperrt wird.

  3. wo ist die Verzögerung von CriticalSection überhaupt? Es sollte ein Mitglied von Log sein.

  4. kennen Sie std::mutex?

  5. Warum übergeben Sie Strings nach Wert? es ist sehr uneffizient. Pass dann durch const Referenz.

  6. Sie verwenden snake_case für einige der Variablen (file_path) aber oberen Kamel für andere (CriticalSection). Verwenden Sie die gleiche Konvention.

  7. str ist nie ein guter Name für eine String-Variable, und der Dateistream ist kein Protokoll. ist die Sache, die die eigentliche Protokollierung tut. logger ist ein besserer Name. In meiner Korrektur heißt es nur m_file_stream.

Corrected Code:

class Log 
{ 

private: 

    std::mutex m_lock; 
    std::ofstream m_file_stream; 
    std::string m_file_path; 

public: 

    Log(const std::string& file_path); 
    void write(const std::string& log); 
}; 

Log::Log(const std::string& file_path): 
    m_file_path(file_path) 
{ 
    m_file_stream.open(m_file_path.c_str()); 
    if (!m_file_stream.is_open() || !m_file_stream.good()) 
    { 
     //throw relevant exception. 
    } 
} 

void Log::write(const std::string& log) 
{ 
    std::lock_guard<std::mutex> lock(m_lock); 
    m_file_stream << log << '\n'; 
}