2016-07-28 18 views
0

Ich verwende Boost.Log asynchrone Senken (siehe Asynchronous sink frontend). Um ein ordnungsgemäßes Herunterfahren zu erreichen, muss man die Einspeisung von Aufzeichnungen in die asynchronen Senken anmutig stoppen und entleeren. Der Kern hat Methoden zum Hinzufügen und Entfernen von Senken, aber es scheint keine Möglichkeit für einen Client zu sein, Senken zu erhalten oder sie zu besuchen. Die Dokumentation hat eine stop_logging Methode,So stoppen Sie alle asynchronen Senken bei Verwendung von Boost.Log

void stop_logging(boost::shared_ptr<sink_t>& sink) 
{ 
    boost::shared_ptr<logging::core> core = logging::core::get(); 

    // Remove the sink from the core, so that no records are passed to it 
    core->remove_sink(sink); 

    // Break the feeding loop 
    sink->stop(); 

    // Flush all log records that may have left buffered 
    sink->flush(); 

    sink.reset(); 
} 

aber es dauert einen bestimmten sink_t Typen. Die Frontend-Klasse enthält Vorlagenargumente für die Sink-Backend- und Warteschlangenstrategie.

template<typename SinkBackendT, 
      typename QueueingStrategyT = unbounded_fifo_queue> 
    class asynchronous_sink; 

werde ich verschiedene Arten von Senken haben, so möchte ich einen generischen Container haben, der sie hält, so kann ich einfach Iterierte darüber und rufen stop_logging für jedes Waschbecken im Behälter.

Dies ist wirklich eine allgemeine Frage zu C++ Template-Datenstrukturen, die ich wegen der in Boost.Log bereitgestellten Schnittstelle adressieren muss. Was ist eine gute Datenstruktur, um asynchrone Senken zu verfolgen, die ich dem Boost.Log-Kern hinzugefügt habe? Ich brauche einen, damit ich beim Herunterfahren stop_logging anrufen kann.

Mein erster einfältiger Ansatz ist, einen Vektor boost::any Objekte zu haben. Aber das ist ziemlich umständlich und unelegant. Ich vermute, dass ein vernünftiger Ansatz wäre, einen Vektor von Funktionsobjekten zu haben, die Lambda-Methoden sind, die stop_logging aufrufen. Aber ich verliere mich in den Schablonentypen und weiß nicht, wie ich das machen soll.

Ich schätze jede Hilfe. Danke!

Antwort

1

Die direkteste Lösung wäre, einen Container mit Funktionsobjekten zu haben, wie Sie vorgeschlagen haben. Zum Beispiel:

std::vector< std::function< void() > > stop_functions; 

// For every asynchronous sink you add 
stop_functions.emplace_back([sink]() 
{ 
    sink->flush(); 
    sink->stop(); 
}); 

In diesem Beispiel sink kann ein Zeiger auf jede Instanz von asynchronous_sink sein, dass Sie die Protokollierung Kern hinzuzufügen passieren. Wenn die Anwendung beendet haben Sie gerade in dem Behälter die gespeicherten Funktionen alle rufen:

for (auto& stop : stop_functions) 
    stop(); 

Allerdings gibt es eine Boost.Signals2 Bibliothek, die allows diesen Prozess ein wenig zu vereinfachen. Sie können ein Signal erzeugen und dann die Funktionen es wie folgt verbinden:

boost::signals2::signal< void() > stop_signal; 

// For every asynchronous sink you do 
stop_signal.connect([sink]() 
{ 
    sink->flush(); 
    sink->stop(); 
}); 

Dann, indem das Signal Aufruf finden Sie alle angeschlossenen Funktionsobjekt anrufen, effektiv jedes Waschbecken zu stoppen.

stop_signal(); 

In jedem Fall können Sie std::bind oder andere Mittel verwenden, um die Funktion zum Erstellen von Objekten Sie mögen. Der wesentliche Teil besteht darin, den Zeiger auf das Sink-Frontend mit seinem Typ in das Funktionsobjekt zu speichern.