cout



  • ...



  • Nein, das wurde aber auch schon mehrfach hier gesagt. 0 wird als streambuf-Zeiger genutzt. Darum ist dieser Stream nicht mit einem streambuf assoziiert. Mit diesem Wissen kannst Du jetzt:

    Was soll ein ostream sein, der nirgendwohin schreibt (oder technisch gesprochen: Der nicht mit einem streambuf assoziiert ist.)?

    verstehen und hast somit meine Antwort "Nein" bestätigt.



  • ...



  • Hm ja, man könnte den streambuf nullen, um einen Logger auszustellen oder so.

    Und wenn der Stream einmal kaputt ist, wird das durch sentry auch sofort fest gestellt, wobei Werner Mal meinte, dass sentry Zeit kostet. Aber vermutlich liegt das am flush() oder am Lock des streambufs, was beides nicht geschieht, wenn der streambuf 0 ist. Ich wusste btw. gar nicht, dass die Streams threadsafe ist?



  • Streams sind garantiert nicht thread-safe.

    Für ein Logger sollte man ein Makro oder eine Funktion mit einem Makro nutzen. Dann fliegts nämlich ganz raus. Alles andere geht auf die Performance.



  • Dennoch nutzt mein MSVC im sentry-Objekt einen Lock und der nutzt einen Mutex. Und auf die Performance geht das so gut wie gar nicht, weil der Stream nach einem fehlerhaften Schreibversuch "gefailt" wird und danach nur noch das Flag abgefragt wird.



  • Eisflamme schrieb:

    Dennoch nutzt mein MSVC im sentry-Objekt einen Lock und der nutzt einen Mutex. Und auf die Performance geht das so gut wie gar nicht, weil der Stream nach einem fehlerhaften Schreibversuch "gefailt" wird und danach nur noch das Flag abgefragt wird.

    Es hängt auch davon ab, was alles geloggt wird und zu welchem Zweck. Mir ging es um ein Logging, dass nur für Debug-Zwecke aktiviert ist. Wenn man dann in einer Schleife auch im Release ins leere loggt, dann hat das sehr wohl ein Performanceeinfluss. Nicht zuletzt auch wegen der Auflösung der Streammanipulatoren.

    Die Threadsafety der Streams ist von der Implementierung abhängig. Ein paar Dinge synchronisieren sie alle, da sie ohne gar nicht funktionieren würden. Eine grundsätzliche Threadsafety kann man aber nicht erwarten und ist im besten Fall einfach der Impelemntierung zu verdanken.



  • Ja, der Std. garantiert auch keine Threadsafety, glaube ich.

    Nicht zuletzt auch wegen der Auflösung der Streammanipulatoren.

    Das verstehe ich nicht, könntest Du das erläutern?



  • Um sicherzustellen, dass auch alles ausgegeben wird musst du std::endl nutzen. Ansonsten verleibt was im Puffer. Im Puffer darf aber nichts bleiben, da du sonst Probleme mit den anderen Threads bekommst.

    Das heißt, du musst nach jeder Ausgabe den Puffer leeren. Das geht auf die Performance. Vorallem wenn es sehr kleine, aber viele Ausgaben sind.



  • Und wo genau geht das auf die Performance, wenn streambuf 0 ist? In Flush prüft der vorm sync (die eigentliche Arbeit vom Flush, richtig?), ob der Stream gefailt ist. Also passiert da doch nichts.



  • Eisflamme schrieb:

    Und wo genau geht das auf die Performance, wenn streambuf 0 ist? In Flush prüft der vorm sync (die eigentliche Arbeit vom Flush, richtig?), ob der Stream gefailt ist. Also passiert da doch nichts.

    Wenn ich
    log<<0.78789;
    mache, dann muss das ja irgendwohin geschrieben werden. Auch wenn es gleich wieder verworfen wird, so wandelt der operator<< für double das Ding erstmal in einen string um - das kostet Zeit.



  • Shade Of Mine schrieb:

    Wenn ich
    log<<0.78789;
    mache, dann muss das ja irgendwohin geschrieben werden. Auch wenn es gleich wieder verworfen wird, so wandelt der operator<< für double das Ding erstmal in einen string um - das kostet Zeit.

    lol



  • Shade Of Mine schrieb:

    Wenn ich
    log<<0.78789;
    mache, dann muss das ja irgendwohin geschrieben werden. Auch wenn es gleich wieder verworfen wird, so wandelt der operator<< für double das Ding erstmal in einen string um - das kostet Zeit.

    Dem ist nicht so - wenn kein streambuf vorhanden ist (nach ostream out(0)), dann ist der Stream im Zustand 'bad'.
    Ruft man nun mit 'log<<0.78789;' den extractor für double auf, dann wird ein sentry-Objekt angelegt, welches im Konstruktor die Fehlerbits des Streams prüft, feststellt, dass da nichts geht und zurückkommt. Im Extractor wird das sentry-Objekt abgefragt, für !ok befunden, anschließend wird der Extraktor verlassen.

    Das sentry-Objekt benötigt nur genau dann (etwas) mehr Zeit, wenn der Stream ok ist. Dann holt es sich die lokale (am Stream hängende) ctype-Facette und prüft zunächst alles auf White Space Character, um diese anschließend zu überlesen, wenn welche da stehen und 'skipws' aktiv ist.
    Im Fehlerfall geschieht dies alles nicht.

    Gruß
    Werner



  • Edit: Zu langsam 🙂

    Ne, weil basic_ostream init aufruft und dort steht:

    if (_Mystrbuf == 0)
    			setstate(badbit);
    

    Und operator<<(double):

    _Myt& __CLR_OR_THIS_CALL operator<<(double _Val)
    		{	// insert a double
    		ios_base::iostate _State = ios_base::goodbit;
    		const sentry _Ok(*this);
    
    		if (_Ok)
    			{	// state okay, use facet to insert
    			const _Nput& _Nput_fac = _USE(ios_base::getloc(), _Nput);
    
    			_TRY_IO_BEGIN
    			if (_Nput_fac.put(_Iter(_Myios::rdbuf()), *this,
    				_Myios::fill(), _Val).failed())
    				_State |= ios_base::badbit;
    			_CATCH_IO_END
    			}
    
    		_Myios::setstate(_State);
    		return (*this);
    		}
    

    Die Konvertierung erfolgt erst bei put der Facette.



  • double war jetzt nur ein Beispiel...
    Dann nehmen wir halt MyDouble als Typ.



  • Und wie soll davon die Implementierung aussehen? Der nutzt doch höchstwahrscheinlich operator<< für die Attribute oder nicht?

    Oder ist das ein Typ, der ein byteweises Schreiben erfordert und daher z.B. write oder selber put nutzt? Selbst dann wird stets ein sentry-Objekt erstellt. Das macht jede Schreibfunktion auf der obersten Ebene. Und schreibt man sich eigene Funktionen, um z.B. die Performance zu erhöhen, ist man stets dazu angehalten selbst ein sentry-Objekt zu nutzen. Wenn man auch das nicht tut, dann ist man wohl selbst schuld.



  • Stell dir vor MyDouble arbeitet intern mit GMP.

    PS:
    Natuerlich kann man immer die Verantwortung an andere Uebertragen. Loest natuerlich jedes Performance Problem. Im Notfall einfach schnellere Hardware kaufen.

    PPS:
    Und spaetestens hier willst du ein Makro haben:
    log<<teureDebugFunktion();



  • Hier wird nicht ernsthaft über etwas diskutiert, was kein normaler Programmierer je machen würde?!



  • Na ja, der Verweis auf GMP hilft mir nicht, da ich es nicht kenne.

    Und wenn ein operator<< wirklich so enorm teuer ist, dann lohnt es sich in der Tat vorher zu prüfen, ob der Stream ok ist und sich entsprechende Operationen zu sparen.

    In 99% der Fälle, wenn operator<< eingesetzt wird - so würde ich behaupten - fängt sentry aber einen Schreibvorgang ab.

    Natuerlich kann man immer die Verantwortung an andere Uebertragen. Loest natuerlich jedes Performance Problem.

    Ich weiß nicht, worauf Du Dich jetzt beziehst. Viel Argumentationsgewalt sehe ich hinter deinem PS jedoch nicht.

    Edit: Ja klar kann man sich die Diskussion sparen. Aber die Aussage, dass operator<< im Falle eines fehlenden streambufs zu teuer ist, halte ich eben für nicht korrekt. Bei den Basistypen wird vom Standard Sorge getragen, dass keine Kosten entstehen. Wenn jemand einen operator<< schreibt, der dasselbe nicht tut, liegt das Problem selbstverständlich bei ihm. Dass man so keine Protokollierung an- oder ausschalten sollte (wobei mich gerade schon interessieren würde, wieso eigentlich nicht?), will ich damit ja nicht bestreiten.



  • Eisflamme schrieb:

    Dass man so keine Protokollierung an- oder ausschalten sollte (wobei mich gerade schon interessieren würde, wieso eigentlich nicht?), will ich damit ja nicht bestreiten.

    Dann ist ja OK.
    Ich hatte angst du wolltest genau das machen.


Anmelden zum Antworten