Asynchrone Thread-sichere Protokollierung in C ++ (kein Mutex)

7

Ich suche eigentlich nach einer Möglichkeit, eine asynchrone und Thread-sichere Protokollierung in meinem C ++ durchzuführen.

Ich habe thread-sichere Protokollierungslösungen wie log4cpp, log4cxx, Boost: log oder rlog bereits erforscht, aber es scheint, dass alle einen Mutex verwenden. Und soweit ich weiß, ist Mutex eine synchrone Lösung, was bedeutet, dass alle Threads gesperrt sind, während sie versuchen, ihre Nachrichten zu schreiben, während andere tun.

Kennst du eine Lösung?

    
Olivier Ramon 16.11.2011, 10:36
quelle

6 Antworten

6

Ich denke, Ihre Aussage ist falsch: die Verwendung von Mutex ist nicht gleichbedeutend mit einer synchronen Lösung. Ja, Mutex ist für die Synchronisationssteuerung gedacht, kann aber für viele verschiedene Dinge verwendet werden. Wir können Mutex beispielsweise in einer Producer-Consumer-Warteschlange verwenden, während die Protokollierung noch asynchron erfolgt.

Ehrlich gesagt habe ich nicht in die Implementierung dieser Logging-Bibliothek geschaut, aber es sollte möglich sein, einen asynchronen Appender (für log4j wie lib) zu erstellen, welcher Logger in eine Producer-Consumer-Queue schreibt und ein anderer Worker-Thread dafür verantwortlich ist Datei (oder sogar an einen anderen Appender delegieren), falls sie nicht bereitgestellt wird.

Bearbeiten: Habe gerade einen kurzen Scan in log4cxx gemacht, es stellt einen AsyncAppender zur Verfügung, der das tut, was ich vorgeschlagen habe: puffert das eingehende Logging-Ereignis und delegiert asynchron an den angehängten Appender.

    
Adrian Shum 16.11.2011 11:19
quelle
5

Ich würde empfehlen, das Problem zu vermeiden, indem Sie nur einen Thread für die Protokollierung verwenden. Um die erforderlichen Daten zur Protokollierung zu übergeben, können Sie eine sperrfreie Fifo-Warteschlange verwenden (threadsicher, solange Hersteller und Verbraucher streng getrennt sind und nur ein Thread jede Rolle hat - daher benötigen Sie für jeden Erzeuger eine Warteschlange.)

Ein Beispiel für eine schnelle, blockierungsfreie Warteschlange ist enthalten:

queue.h:

%Vor%

hybridqueue.h:

%Vor%     
Erbureth 16.11.2011 11:04
quelle
5

Wenn ich Ihre Frage richtig beantworte, sind Sie besorgt, E / A-Operationen (wahrscheinlich schreibt man in eine Datei) im kritischen Bereich eines Loggers durchzuführen.

Mit

Boost: log können Sie ein benutzerdefiniertes Writer-Objekt definieren. Sie können operator () so definieren, dass sie asynchrone E / A aufruft oder eine Nachricht an Ihren Logging-Thread (der I / Os ausführt) weiterleitet.

Ссылка

    
Daszek 16.11.2011 11:08
quelle
2

Keine Bibliothek wird das tun, soweit ich weiß - es ist zu komplex. Sie müssen selbst rollen, und hier ist eine Idee, die ich gerade hatte, erstellen Sie eine Pro-Thread-Protokolldatei, stellen Sie sicher, dass das erste Element in jedem Eintrag ein Zeitstempel ist, und führen Sie die Protokolle anschließend zusammen ausführen und sortieren (nach Zeitstempel) ), um eine endgültige Protokolldatei zu erhalten.

Sie können einen lokalen Thread-Speicher verwenden (sagen wir% aco_de% handle AFAIK, es ist nicht möglich, ein Stream-Objekt im lokalen Thread-Speicher zu speichern) und suchen diese Handle in jeder Protokollzeile nach und schreiben auf diesen spezifischen Datei.

All diese Komplexität gegen das Sperren des Mutex? Ich kenne nicht die Leistungsanforderungen Ihrer Anwendung, aber wenn es empfindlich ist - warum würden Sie (exzessiv) protokollieren? Denken Sie über andere Möglichkeiten nach, die benötigten Informationen ohne Protokollierung zu erhalten?

Auch eine andere Sache zu betrachten ist, den Mutex für den geringstmöglichen Zeitraum zu verwenden, d. h. zuerst den Protokolleintrag erstellen und dann kurz vor dem Schreiben in die Datei die Sperre übernehmen.

    
Nim 16.11.2011 10:52
quelle
1

Lock-free-Algorithmen sind nicht unbedingt die schnellsten. Definieren Sie Ihre Grenzen. Wie viele Threads gibt es für die Protokollierung? Wie viel wird maximal in einer einzigen Protokolloperation geschrieben?

I / O-gebundene Operationen sind viel langsamer als Threadkontextwechsel aufgrund blockierender / aufwachender Threads. Die Verwendung des Lock-Free / Locking-Lock-Algorithmus mit 10 Schreib-Threads bringt eine schwere Last in die CPU.

Sperren Sie in Kürze andere Threads, wenn Sie in eine Datei schreiben.

    
ali_bahoo 16.11.2011 11:25
quelle
0

In einem Windows-Programm verwenden wir eine benutzerdefinierte Windows-Nachricht. Zuerst wird Speicher für den Protokolleintrag auf dem Heap reserviert. Dann wird PostMessage mit dem Zeiger als LPARAM und der Datensatzgröße als WPARAM aufgerufen. Das Empfängerfenster extrahiert den Datensatz, zeigt ihn an und speichert ihn in der Protokolldatei. Dann kehrt PostMessage zurück und der zugewiesene Speicher wird vom Absender freigegeben. Dieser Ansatz ist threadsicher, und Sie müssen keine Mutexe verwenden. Die Parallelität wird durch den Nachrichtenwarteschlangenmechanismus von Windows gehandhabt. Nicht sehr elegant, aber funktioniert.

    
kol 16.11.2011 10:49
quelle