Erstellt einen separaten Thread für einen Logger ok?

8

Ich schreibe eine Multithreadanwendung in Qt (mehrere Threads mit ihren eigenen Ereignisschleifen). Bei der Protokollierung möchte ich, dass der Logger eine Thread-ID (mit aussagekräftigen Namen) in das Protokoll aufnimmt. Der Qt-Standard-Logger scheint dazu nicht in der Lage zu sein. Also habe ich drei Möglichkeiten:

  1. Jeder Thread protokolliert selbst (dies beinhaltet Mutexe, also ist das wahrscheinlich der schlechteste Ansatz, aber ich bin mir nicht sicher)
  2. Es gibt einen dedizierten Logger-Thread und andere Threads , die Ereignisse direkt in eintragen (wahrscheinlich schneller als 3.)
  3. Wie 2., aber die Nachricht wird über das Signal / Slot-System gesendet (in der Tat wird dies dazu führen, dass auch ein Ereignis veröffentlicht wird).

Welcher ist besser und was sind die besten Praktiken im Allgemeinen?

Einige Dinge, um nach Fragen in Kommentaren zu klären:

  • QThread hat eine Standardmethode postEvent() , die Thread-sicher ist.
  

Es stellt sich also die Frage, ob der Logger-Thread genügend Arbeit pro Ereignis machen muss, um die Kosten für das Marshallen der Ereignisdaten über eine Art von Warteschlange zu rechtfertigen.

  • Das ist die Essenz der Frage. Ich weiß, dass die beste Antwort "Messen!" Ist, aber derzeit befindet sich die App in einer frühen Entwicklungsphase, es gibt nicht viel zu messen. Es ist auch immer gut, von Anfang an das richtige Design zu wählen.
  • In meinem Fall sind Threads wahrscheinlich eine gute Idee: Es ist ein Media Player, also gibt es GUI-Thread, Wiedergabe-Thread, DB / Media-Bibliothek Thread, Netzwerk-Thread-Pool ... Der ganze Zoo von Threads mit anderen Worten.
Viacheslav Kroilov 02.08.2016, 15:55
quelle

3 Antworten

8

Dies sind allgemeine Bemerkungen, da ich keine Erfahrung mit Qt habe. Im Hinblick auf die Kosten des Einreihens im Allgemeinen: I / O lässt normalerweise andere Laufzeitkosten verblassen, also sollte es keine Rolle spielen.

Eigenschaften eines dedizierten Logging-Threads:

  • Gut: Minimale Auswirkung auf das Laufzeitverhalten des Programms.
  • Gut: Garantierte einzelne Protokollnachrichten (keine gemischte Ausgabe von mehreren Threads).
  • Schlecht: Signifikanter Implementierungsaufwand.
  • Schlecht: Der Zeitpunkt der Initiierung und eigentlichen Protokollierung ist entkoppelt (das ist der springende Punkt!). Möglicherweise sehen Sie die Protokollierung nicht dort, wo Sie sie erwarten.
  • Schlecht: Ein terminierendes Programm kann die letzten und wichtigsten Log-Nachrichten (Andreas-Punkt) schlucken, also können Sie eine synchrone Log-Funktion hinzufügen (das ist ein Extrem des obigen Punktes).

Die (Vor-) Vorteile der direkten Protokollierung von jedem Thread sind die Umkehrung des Obigen. Keine zwei Threads können gleichzeitig protokollieren (entweder weil Funktionen wie printf() implizit eine FILE sperren, oder weil Sie die Protokollfunktion explizit synchronisieren); Dadurch werden alle Threads, die protokolliert werden sollen, blockiert, bis der aktuelle Thread ausgeführt wird. Wenn die Protokollierung zu Debugging-Zwecken durchgeführt wird, kann es erforderlich sein, ungepuffert zu protokollieren (damit die Daten bei einem nachfolgenden Absturz nicht verloren gehen), wodurch sich die Auswirkungen auf die Laufzeit verschlechtern.

Wie schlecht das ist, hängt von der Art der Anwendung sowie vom Protokollierungsmechanismus und der Datenmenge ab.

    
Peter A. Schneider 02.08.2016, 16:38
quelle
2

Ich habe Logging-Mechanismen für Qt-Anwendungen mit dem Qt-Event-Mechanismus sauber implementiert.

In einer Qt-Anwendung gibt es eine einzelne Instanz von QApplication , die die Anwendung darstellt.

Sie können Ihre eigenen Ereignisse erstellen, indem Sie von QEvent erben und sie veröffentlichen und mit den QApplication-Objekt für die Anwendung.

So haben Sie zum Beispiel Ihre Log-Ereignisklasse

%Vor%

Und Sie können Ereignisse aus jedem Qt-Thread mit

posten %Vor%

Der Handler könnte ein Hauptfensterobjekt (wenn Sie in ein Fenster loggen wollen) oder ein dediziertes Objekt sein, wenn Sie z.B. Log in eine Datei.

Überschreiben Sie in dem Objekt, das die Ereignisse behandelt, QObject :: event, um die Protokollnachrichten zu verarbeiten

%Vor%     
docsteer 02.08.2016 18:13
quelle
1

Ich verstehe nicht ganz, warum jeder Thread, der die Protokollierung selbst durchführt, einen expliziten Mutex verwenden müsste.

Wenn Sie sich bei einer Datenträgerdatei anmelden, kann jeder Thread in einer eigenen Datei protokollieren. Sie können die Dateien mit einem gemeinsamen Präfix benennen:

%Vor%

Das Betriebssystem serialisiert den Zugriff über seine Dateisystem-Mutex (s).

Wenn Sie sich bei einer Datenbank anmelden, die den gleichzeitigen Zugriff unterstützt, wie zum Beispiel sqlite mit ausgewählten Optionen für den gemeinsamen Zugriff, wird der Datenbanktreiber für den Serialisierungszugriff zuständig sein.

Wenn Sie sich bei einem gemeinsamen Thread anmelden, hat die Ereigniswarteschlange einen Mutex, mit dem Sie automatisch serialisieren, wenn Sie postEvent .

Sie haben Recht, dass Sie mit dem Signal-Slot-Mechanismus nicht viel Zeit für die direkte Verwendung von Ereignissen benötigen. In der Tat wird garantiert, dass mehr Speicherzuweisungen vorgenommen werden. Daher sollten Sie lieber selbst ein Ereignis posten, idealerweise ein Ereignis, das QVarLengthArray<char> einer Größe verwendet, die "den meisten" Protokollmeldungen entspricht. Dann wird ein solches Ereignis mit einem einzigen malloc -Aufruf zugewiesen:

%Vor%

Hätten Sie eine QByteArray oder eine QString verwendet, hätte der Ausdruck new MyLogEvent mindestens zwei Zuordnungen ausgeführt.

    
Kuba Ober 02.08.2016 22:12
quelle

Tags und Links